ado.net最佳实践

Ado.net最佳实践

http://www.dotnetfamily.com/news/newsfiles/20066252228705.html

要通过应用程序执行以下操作,就要使用 DataSet

在结果的多个离散表之间进行导航。

操作来自多个数据源(例如,来自多个数据库、一个 XML 文件和一个电子表格的混合数据)的数据。

在各层之间交换数据或使用 XML Web 服务。与 DataReader 不同的是,DataSet 能传递给远程客户端。

重用同样的行组,以便通过缓存获得性能改善(例如排序、搜索或筛选数据)。

每行执行大量处理。对使用 DataReader 返回的每一行进行扩展处理会延长服务于 DataReader 的连接的必要时间,这影响了性能。

使用 XML 操作对数据进行操作,例如可扩展样式表语言转换(XSLT 转换)或 XPath 查询。

对于下列情况,要在应用程序中使用 DataReader

不需要缓存数据。

要处理的结果集太大,内存中放不下。

一旦需要以只进、只读方式快速访问数据。

 

 

DataSet 中搜索数据

DataSet 中查询与特定条件相匹配的行时,可以利用基于索引的查找提高搜索性能。当把 PrimaryKey 值赋给 DataTable 时,会创建一个索引。当给 DataTable 创建 DataView 时,也会创建一个索引。

如果对组成 DataTable PrimaryKey的列进行查询,要使用 DataTable.Rows.Find 而不是 DataTable.Select

如果对组成 DataTable PrimaryKey的列进行查询,要使用 DataTable.Rows.Find 而不是 DataTable.Select

对于涉及到非主键列的查询,可以使用 DataView 为数据的多个查询提高性能。当把排序顺序应用到 DataView 时,就会建立一个搜索时使用的索引。DataView 公开 Find FindRows 方法,以便查询基础 DataTable 中的数据。

如果不需要表的排序视图,仍可以通过为 DataTable 创建 DataView 来利用基于索引的查找。注意,只有对数据执行多个查询操作时,这样才会带来好处。如果只执行单一查询,创建索引所需要的处理就会降低使用索引所带来的性能提升。

 

批处理 SQL 语句

很多数据库支持把多条命令合并或批处理成一条单一命令执行。例如,SQL Server 使您可以用分号 (;) 分隔命令。把多条命令合并成单一命令,能减少到服务器的行程数,并提高应用程序的性能。例如,可以把所有预定的删除在应用程序中本地存储起来,然后再发出一条批处理命令调用,从数据源删除它们。

 

当访问列数据时,使用类型化访问器,例如,GetStringGetInt32 。这使您不用进行将 GetValue 返回的 Object 强制转换成特定类型所需的处理。

例如:

[C#]
public void ReadMyData(string myConnString) {
string mySelectQuery = "SELECT OrderID, CustomerID FROM Orders";
OleDbConnection myConnection = new OleDbConnection(myConnString);
OleDbCommand myCommand = new OleDbCommand(mySelectQuery,myConnection);
myConnection.Open();
OleDbDataReader myReader;
myReader = myCommand.ExecuteReader();
// Always call Read before accessing data.
while (myReader.Read()) {
Console.WriteLine(myReader.GetInt32(0) + ", " + myReader.GetString(1));
}
// always call Close when done reading.
myReader.Close();
// Close the connection when done with it.
myConnection.Close();
}

默认情况下,DataReader 每次 Read 时都要把整行加载到内存。这允许在当前行内随机访问列。如果不需要这种随机访问,为了提高性能,就把 CommandBehavior.SequentialAccess 传递给 ExecuteReader 调用。这将 DataReader 的默认行为更改为仅在请求时将数据加载到内存。注意,CommandBehavior.SequentialAccess 要求顺序访问返回的列。也就是说,一旦读过返回的列,就不能再读它的值了。

 

如果已经完成读取来自 DataReader 的数据,但仍然有大量挂起的未读结果,就在调用 DataReader Close 之前先调用 Command Cancel。调用 DataReader Close 会导致在关闭游标之前检索挂起的结果并清空流。调用 Command Cancel 会放弃服务器上的结果,这样,DataReader 在关闭的时候就不必读这些结果。如果要从 Command 返回输出参数,还要调用 Cancel 放弃它们。如果需要读取任何输出参数,不要调用 Command Cancel,只要调用 DataReader Close 即可。

 

二进制大对象 (BLOB)

DataReader 检索二进制大对象 (BLOB) 时,应该把 CommandBehavior.SequentialAccess 传递给 ExecuteReader 方法调用。因为 DataReader 的默认行为是每次 Read 都把整行加载到内存,又因为 BLOB 值可能非常大,所以结果可能由于单个 BLOB 而使大量内存被用光。SequentialAccess DataReader 的行为设置为只加载请求的数据。然后还可以使用 GetBytes GetChars 控制每次加载多少数据。

记住,使用 SequentialAccess 时,不能不按顺序访问 DataReader 返回的不同字段。也就是说,如果查询返回三列,其中第三列是 BLOB,并且想访问前两列中的数据,就必须在访问 BLOB 数据之前先访问第一列的值,然后访问第二列的值。这是因为现在数据是顺序返回的,并且 DataReader 一旦读过该数据,该数据就不再可用。

 

 

使用 SqlCommand 执行存储过程的快速提示:如果调用存储过程,将 SqlCommand CommandType 属性指定为 StoredProcedure CommandType。这样通过将该命令显式标识为存储过程,就不需要在执行之前分析命令 所以显示指定命令类型是很有必要的。

 

测试 Null

如果表(在数据库中)中的列允许为空,就不能测试参数值是否等于空。相反,需要写一个 WHERE 子句,测试列和参数是否都为空。下面的 SQL 语句返回一些行,它们的 LastName 列等于赋给 @LastName 参数的值,或者 LastName 列和 @LastName 参数都为空。

SELECT * FROM Customers
    
    
WHERE ((LastName = @LastName) OR (LastName IS NULL AND @LastName IS NULL))
    
    

Null 作为参数值传递

对数据库的命令中,当把空值作为参数值发送时,不能使用 nullVisual Basic .NET 中为 Nothing)。而需要使用 DBNull.Value。例如:


  
  
   
    
  
  
//C#
    
    
SqlParameter param = new SqlParameter("@Name", SqlDbType.NVarChar, 20);
    
    
param.Value = DBNull.Value;
    
    

 

public void RunSqlTransaction(SqlDataAdapter da, SqlConnection myConnection, DataSet ds)
    
    
{
    
    
  myConnection.Open();
    
    
  SqlTransaction myTrans = myConnection.BeginTransaction();
    
    
  myCommand.Transaction = myTrans;
    
    

  
  
   
    
  
  
  try
    
    
  {
    
    
    da.Update(ds);
    
    
    myCommand.Transaction.Commit();
    
    
    Console.WriteLine("Update successful.");
    
    
  }
    
    
  catch(Exception e)
    
    
  {
    
    
    try
    
    
    {
    
    
      myTrans.Rollback();
    
    
    }
    
    
    catch (SqlException ex)
    
    
    {
    
    
      if (myTrans.Connection != null)
    
    
      {
    
    
        Console.WriteLine("An exception of type " + ex.GetType() +
    
    
                          " was encountered while attempting to roll back the transaction.");
    
    
      }
    
    
    }
    
    

  
  
   
    
  
  
    Console.WriteLine(e.ToString());
    
    
    Console.WriteLine("Update failed.");
    
    
  }
    
    
  myConnection.Close();
    
    

}

 

 

 

 

 

对于 C# 程序员来说,确保始终关闭 Connection DataReader 对象的一个方便的方法就是使用 using 语句。using 语句在离开自己的作用范围时,会自动调用被使用的对象的 Dispose。例如:

//C#
    
    
string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
    
    

  
  
   
    
  
  
using (SqlConnection conn = new SqlConnection(connString))
    
    
{
    
    
  SqlCommand cmd = conn.CreateCommand();
    
    
  cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
    
    
  
    
    
  conn.Open();
    
    

  
  
   
    
  
  
  using (SqlDataReader dr = cmd.ExecuteReader())
    
    
  {
    
    
    while (dr.Read())
    
    
      Console.WriteLine("{0}/t{1}", dr.GetString(0), dr.GetString(1));
    
    
  }
    
    
}
    
    

 

 

 

避免访问 OleDbConnection.State 属性

如果连接已经打开,OleDbConnection.State 属性会对 DBPROP_CONNECTIONSTATUS 属性的 DATASOURCEINFO 属性集执行本地 OLE DB 调用 IDBProperties.GetProperties,这可能会导致对数据源的往返行程。也就是说,检查 State 属性的代价可能很高。所以仅在需要时检查 State 属性。如果需要经常检查该属性,监听 OleDbConnection StateChange 事件可能会使应用程序的性能好一些。

 

 

 

 

 

避免自动增量值冲突

就像大多数数据源一样,DataSet 使您可标识那些添加新行时自动对其值进行递增的列。在 DataSet 中使用自动增量的列时,如果自动增量的列来自数据源,可避免添加到 DataSet 的行和添加到数据源的行之间本地编号冲突。

例如,考虑一个表,它的主键列 CustomerID 是自动增量的。两个新的客户信息行添加到表中,并接收到自动增量的 CustomerID 1 2。然后,只有第二个客户行被传递给 DataAdapter 的方法 Update,新添加的行在数据源接收到一个自动增量的 CustomerID 1,与 DataSet 中的值 2 不匹配。当 DataAdapter 用返回值填充表中第二行时,就会出现约束冲突,因为第一个客户行已经使用了 CustomerID 1

要避免这种情况,建议在使用数据源上自动增量的列以及 DataSet 上自动增量的列时,把 DataSet 中的列创建为 AutoIncrementStep 值等于 -1 并且 AutoIncrementSeed 值等于 0,另外,还要确保数据源生成的自动增量标识值从 1 开始,并且以正阶值递增。因此,DataSet 为自动增量值生成负数,与数据源生成的正自动增量值不冲突。另外一个选择是使用 Guid 类型的列,而不是自动增量的列。生成 Guid 值的算法应该永远不会使数据源中生成的 Guid 值与 DataSet 中生成的 Guid 值一样。

如果自动增量的列只是用作唯一值,而且没有任何意义,就考虑使用 Guid 代替自动增量的列。它们是唯一的,并且避免了使用自动增量的列所必需的额外工作。

 

检查开放式并发冲突

按照设计,由于 DataSet 是与数据源断开的,所以,当多个客户端在数据源上按照开放式并发模型更新数据时,需要确保应用程序避免冲突。

在测试开放式并发冲突时有几项技术。一项技术涉及在表中包含时间戳列。另外一项技术是,验证一行中所有列的原始值是否仍然与通过在 SQL 语句中使用 WHERE 子句进行测试时在数据库中找到的值相匹配。

多线程编程

ADO.NET 对性能、吞吐量和可伸缩性进行优化。因此,ADO.NET 对象不锁定资源,并且必须只用于单线程。一个例外是 DataSet,它对多个阅读器是线程安全的。但是,在写的时候需要把 DataSet 锁定。

 



关于强类型dataset

使用强类型 DataSet 的好处

DataSet 的另一个好处是可被继承以创建一个强类型 DataSet。强类型 DataSet 的好处包括设计时类型检查,以及 Microsoft Visual Studio .NET 用于强类型 DataSet 语句结束所带来的好处。修改了 DataSet 的架构或关系结构后,就可以创建一个强类型 DataSet,把行和列作为对象的属性公开,而不是作为集合中的项公开。例如,不公开客户表中行的姓名列,而公开 Customer 对象的 Name 属性。类型化 DataSet DataSet 类派生,因此不会牺牲 DataSet 的任何功能。也就是说,类型化 DataSet 仍能远程访问,并作为数据绑定控件(例如 DataGrid)的数据源提供。如果架构事先不可知,仍能受益于通用 DataSet 的功能,但却不能受益于强类型 DataSet 的附加功能

处理强类型 DataSet 中的空引用

使用强类型 DataSet 时,可以批注 DataSet XML 架构定义语言 (XSD) 架构,以确保强类型 DataSet 正确处理空引用。nullValue 批注使您可用一个指定的值 String.Empty 代替 DBNull、保留空引用或引发异常。选择哪个选项取决于应用程序的上下文。默认情况下,如果遇到空引用,就会引发异常。

 

 

以下不大明白

用架构填充 DataSet

当用数据填充 DataSet 时,DataAdapter.Fill 方法使用 DataSet 的现有架构,并使用从 SelectCommand 返回的数据填充它。如果在 DataSet 中没有表名与要被填充的表名相匹配,Fill 方法就会创建一个表。默认情况下,Fill 仅定义列和列类型。

通过设置 DataAdapter MissingSchemaAction 属性,可以重写 Fill 的默认行为。例如,要让 Fill 创建一个表架构,并且还包括主键信息、唯一约束、列属性、是否允许为空、最大列长度、只读列和自动增量的列,就要把 DataAdapter.MissingSchemaAction 指定为 MissingSchemaAction.AddWithKey。或者,在调用 DataAdapter.Fill 前,可以调用 DataAdapter.FillSchema 来确保当填充 DataSet 时架构已到位。

FillSchema 的调用会产生一个到服务器的额外行程,用于检索附加架构信息。为了获得最佳性能,需要在调用 Fill 之前指定 DataSet 的架构,或者设置 DataAdapter MissingSchemaAction

 

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ADO.NET是微软公司针对数据库操作开发的技术框架。它是.NET框架的一部分,提供了一系列用于连接和操作数据库的类和API接口。 ADO.NET技术参考大全是指包含了ADO.NET框架的全部类、方法和属性的详细文档资料。这份资料一般由微软官方提供,用户可以在开发过程中查找与ADO.NET相关的各种技术问题和解决方案。 ADO.NET技术参考大全对于开发者来说非常重要。首先,它提供了完整的ADO.NET框架的文档,使开发者能够全面了解ADO.NET的各个方面,包括连接数据库、执行SQL语句、数据读取和更新、事务处理等。开发者可以根据这份文档,快速掌握ADO.NET的核心概念和用法。 其次,ADO.NET技术参考大全还包含了各种实际应用场景和最佳实践的示例代码,方便开发者学习和参考。这些示例代码可以帮助开发者更好地理解ADO.NET的用法,提高编程效率和质量。 此外,ADO.NET技术参考大全还提供了关于ADO.NET的性能优化、安全性、数据缓存和数据绑定等方面的详细说明,开发者可以根据自己的需求选择适合的技术和策略,提高程序的性能和安全性。 总之,ADO.NET技术参考大全是ADO.NET开发者必备的参考资料,它可以帮助开发者快速上手和深入学习ADO.NET技术,提高开发效率和代码质量。如果您想深入学习ADO.NET开发技术,强烈建议您查阅并参考ADO.NET技术参考大全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值