源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

ADO.NET 的最佳实践技巧

  • 时间:2020-12-25 09:34 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:ADO.NET 的最佳实践技巧
这是我很早以前看过的微软的一篇文章,最近,一些网友问的问题很多理论都在里面,所以,整理一下放在这里,大家可以参考一下。 [h1]简介[/h1] 本文为您提供了在 Microsoft ADO.NET 应用程序中实现和获得最佳性能、可伸缩性以及功能的最佳解决方案;同时也讲述了使用 ADO.NET 中可用对象的最佳实践;并提出一些有助于优化 ADO.NET 应用程序设计的建议。 本文包含:
有关 .NET 框架包含的 .NET 框架数据提供程序的信息。
[b]DataSet[/b] 和 [b]DataReader[/b] 之间的比较,以及这些对象中每个对象最佳用法的解释。
解释如何使用 [b]DataSet[/b]、[b]Commands[/b] 和 [b]Connections[/b]。
有关与 XML 集成的信息。
通用的技巧和问题。
[url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconWorkingWithTypedDataSet.asp]Working with a Typed DataSet[/url]。 [b]刷新 DataSet 中的数据[/b] 如果想用服务器上的更新值刷新 [b]DataSet[/b] 中的值,就使用 [b]DataAdapter.Fill[/b]。如果有在 [b]DataTable[/b] 上定义的主键,[b]DataAdapter.Fill[/b] 会根据主键进行新行匹配,并且当更改到现有行时应用服务器上的值。即使刷新之前修改了它们,刷新行的 [b]RowState[/b] 仍被设置为 [b]Unchanged[/b]。注意,如果没有为 [b]DataTable[/b] 定义主键,[b]DataAdapter.Fill [/b]就用可能重复的主键值添加新行。 如果想用来自服务器的当前值刷新表,并同时保留对表中的行所做的任何更改,必须首先用 [b]DataAdapter.Fill[/b] 填充表,并填充一个新的 [b]DataTable[/b],然后用 [b]preserveChanges[/b] 值 [b]true[/b] 把 [b]DataTable[/b][b]Merge[/b] 到 [b]DataSet[/b] 中。 [b]在 DataSet 中搜索数据[/b] 在 [b]DataSet[/b] 中查询与特定条件相匹配的行时,可以利用基于索引的查找提高搜索性能。当把 [b]PrimaryKey[/b] 值赋给 [b]DataTable[/b] 时,会创建一个索引。当给 [b]DataTable[/b] 创建 [b]DataView[/b] 时,也会创建一个索引。下面是一些利用基于索引进行查找的技巧。
如果对组成 [b]DataTable[/b] 的 [b]PrimaryKey[/b]的列进行查询,要使用 [b]DataTable.Rows.Find[/b] 而不是 [b]DataTable.Select[/b]。
对于涉及到非主键列的查询,可以使用 [b]DataView[/b] 为数据的多个查询提高性能。当把排序顺序应用到 [b]DataView[/b] 时,就会建立一个搜索时使用的索引。[b]DataView[/b] 公开 [b]Find[/b] 和 [b]FindRows[/b] 方法,以便查询基础 [b]DataTable[/b] 中的数据。
如果不需要表的排序视图,仍可以通过为 [b]DataTable[/b] 创建 [b]DataView[/b] 来利用基于索引的查找。注意,只有对数据执行多个查询操作时,这样才会带来好处。如果只执行单一查询,创建索引所需要的处理就会降低使用索引所带来的性能提升。
[b]DataView 构造[/b] 如果创建了 [b]DataView[/b],并且修改了 [b]Sort[/b]、[b]RowFilter[/b] 或 [b]RowStateFilter[/b] 属性,[b]DataView[/b] 就会为基础 [b]DataTable[/b] 中的数据建立索引。创建 [b]DataView[/b] 对象时,要使用 [b]DataView[/b] 构造函数,它用 [b]Sort[/b]、[b]RowFilter[/b] 和 [b]RowStateFilter[/b] 值作为构造函数参数(与基础 [b]DataTable[/b] 一起)。结果是创建了一次索引。创建一个“空”[b]DataView[/b] 并随后设置 [b]Sort[/b]、[b]RowFilter[/b] 或 [b]RowStateFilter[/b] 属性,会导致索引至少创建两次。 [b]分页[/b] ADO.NET 可以显式控制从数据源中返回什么样的数据,以及在 [b]DataSet[/b] 中本地缓存多少数据。对查询结果的分页没有唯一的答案,但下面有一些设计应用程序时应该考虑的技巧。
避免使用带有 [b]startRecord[/b] 和 [b]maxRecords[/b] 值的 [b]DataAdapter.Fill [/b]重载。当以这种方式填充 [b]DataSet[/b] 时,只有 [b]maxRecords[/b] 参数(从 [b]startRecord[/b] 参数标识的记录开始)指定的记录数量用于填充 [b]DataSet[/b],但无论如何总是返回完整的查询。这就会引起不必要的处理,用于读取“不需要的”记录;而且为了返回附加记录,会耗尽不必要的服务器资源。
用于每次只返回一页记录的技术是创建 SQL 语句,把 WHERE 子句以及 ORDER BY 子句和 TOP 谓词组合起来。此技术取决于存在一种可唯一标识每一行的办法。当浏览下一页记录时,修改 WHERE 子句使之包含所有唯一标识符大于当前页最后一个唯一标识符的记录。当浏览上一页记录时,修改 WHERE 子句使之返回所有唯一标识符小于当前页第一个唯一标识符的记录。[u]两种查询都只返回记录的 TOP 页[/u]。当浏览上一页时,需要以降序为结果排序。这将有效地返回查询的最后一页(如果需要,显示之前也许要重新排序结果)。有关这个技术的一个示例,请参阅 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconPagingThroughQueryResult.asp]Paging Through a Query Result[/url]。
另一项每次只返回一页记录的技术是创建 SQL 语句,把 TOP 谓词和嵌入式 SELECT 语句的使用结合在一起。此技术并不依赖于存在一种可唯一标识每一行的办法。使用这项技术的第一步是把所需页的数量与页大小相乘。然后将结果传递给 SQL Query 的 TOP 谓词,该查询以升序排列。再把此查询嵌入到另一个查询中,后者从降序排列的嵌入式查询结果中选择 TOP 页大小。实质上,返回的是嵌入式查询的最后一页。例如,要返回查询结果的第三页(页大小是 10),应该书写如下所示的命令:
SELECT TOP 10 * FROM
      (SELECT TOP 30 * FROM Customers ORDER BY Id ASC) AS Table1
      ORDER BY Id DESC
注意,从查询中返回的结果页以降序显示。如果需要,应该重新排序。
如果数据不经常变动,可以在 [b]DataSet[/b] 中本地维护一个记录缓存,以此提高性能。例如,可以在本地 [b]DataSet[/b] 中存储 10 页有用的数据,并且只有当用户浏览超出缓存第一页和最后一页时,才从数据源中查询新数据。
有关更多信息,请参阅 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/dnbda/html/daag.asp].NET Data Access Architecture Guide[/url]。 [b]用架构填充 DataSet[/b] 当用数据填充 [b]DataSet[/b] 时,[b]DataAdapter.Fill [/b]方法使用 [b]DataSet[/b] 的现有架构,并使用从 [b]SelectCommand[/b] 返回的数据填充它。如果在 [b]DataSet[/b] 中没有表名与要被填充的表名相匹配,[b]Fill[/b] 方法就会创建一个表。默认情况下,[b]Fill[/b] 仅定义列和列类型。 通过设置 [b]DataAdapter[/b] 的 [b]MissingSchemaAction[/b] 属性,可以重写 [b]Fill[/b] 的默认行为。例如,要让 [b]Fill[/b] 创建一个表架构,并且还包括主键信息、唯一约束、列属性、是否允许为空、最大列长度、只读列和自动增量的列,就要把 [b]DataAdapter.MissingSchemaAction[/b] 指定为 [b]MissingSchemaAction.AddWithKey[/b]。或者,在调用 [b]DataAdapter.Fill[/b] 前,可以调用 [b]DataAdapter.FillSchema[/b] 来确保当填充 [b]DataSet[/b] 时架构已到位。 对 [b]FillSchema[/b] 的调用会产生一个到服务器的额外行程,用于检索附加架构信息。为了获得最佳性能,需要在调用 [b]Fill[/b] 之前指定 [b]DataSet[/b] 的架构,或者设置 [b]DataAdapter[/b] 的 [b]MissingSchemaAction[/b]。 [b]使用 CommandBuilder 的最佳实践[/b] 假设 [b]SelectCommand[/b] 执行单一表 SELECT,[b]CommandBuilder[/b] 就会以 [b]DataAdapter[/b] 的 [b]SelectCommand[/b] 属性为基础自动生成 [b]DataAdapter[/b] 的 [b]InsertCommand[/b]、[b]UpdateCommand[/b]、和 [b]DeleteCommand[/b] 属性。下面是为获得最佳性能而使用 [b]CommandBuilder[/b] 的一些技巧。
[b]CommandBuilder[/b] 的使用应该限制在设计时或即席方案中。生成 [b]DataAdapter[/b] 命令属性所必需的处理会影响性能。如果预先知道 INSERT/UPDATE/DELETE 语句的内容,就显式设置它们。一个比较好的设计技巧是,为 INSERT/UPDATE/DELETE 命令创建存储过程并显式配置 [b]DataAdapter[/b] 命令属性以使用它们。
[b]CommandBuilder[/b] 使用 [b]DataAdapter[/b] 的 [b]SelectCommand[/b] 属性确定其他命令属性的值。如果 [b]DataAdapter[/b] 的 [b]SelectCommand[/b] 本身曾经更改过,确保调用 [b]RefreshSchema[/b] 以更新命令属性。
如果 [b]DataAdapter[/b] 命令属性为空(命令属性默认情况下为空),[b]CommandBuilder[/b] 仅仅为它生成一条命令。如果显式设置了命令属性,[b]CommandBuilder[/b] 不会重写它。如果希望 [b]CommandBuilder[/b] 为以前已经设置过的命令属性生成命令,就把命令属性设置为空。
[b]批处理 SQL 语句[/b] 很多数据库支持把多条命令合并或批处理成一条单一命令执行。例如,SQL Server 使您可以用分号 (;) 分隔命令。把多条命令合并成单一命令,能减少到服务器的行程数,并提高应用程序的性能。例如,可以把所有预定的删除在应用程序中本地存储起来,然后再发出一条批处理命令调用,从数据源删除它们。 虽然这样做确实能提高性能,但是,当对 [b]DataSet[/b] 中的数据更新进行管理时,可能会增加应用程序的复杂性。要保持简单,可能要在 [b]DataSet[/b] 中为每个 [b]DataTable[/b] 创建一个 [b]DataAdapter[/b]。 [b]用多个表填充 DataSet[/b] 如果使用批处理 SQL 语句检索多个表并填充 [b]DataSet[/b],第一个表用指定给 [b]Fill[/b] 方法的表名命名。后面的表用指定给 [b]Fill[/b] 方法的表名加上一个从 1 开始并且增量为 1 的数字命名。例如,如果运行下面的代码:
'Visual Basic
Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection)
Dim ds As DataSet = New DataSet()
da.Fill(ds, "Customers")
//C#
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection);
DataSet ds = new DataSet();
da.Fill(ds, "Customers");
来自 Customers 表的数据放在名为 "Customers" 的 [b]DataTable[/b] 中。来自 Orders 表的数据放在名为 "Customers1" 的 [b]DataTable[/b] 中。 填充完 [b]DataSet[/b] 之后,可以很容易地把 "Customers1" 表的 [b]TableName[/b] 属性改为 "Orders"。但是,后面的填充会导致 "Customers" 表被重新填充,而 "Orders" 表会被忽略,并创建另外一个 "Customers1" 表。为了对这种情况作出补救,创建一个 [b]DataTableMapping[/b],把 "Customers1" 映射到 "Orders",并为其他后面的表创建其他的表映射。例如:
'Visual Basic
Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection)
da.TableMappings.Add("Customers1", "Orders")
Dim ds As DataSet = New DataSet()
da.Fill(ds, "Customers")
//C#
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection);
da.TableMappings.Add("Customers1", "Orders");
DataSet ds = new DataSet();
da.Fill(ds, "Customers");
[b]使用 DataReader[/b] 下面是一些使用 [b]DataReader[/b] 获得最佳性能的技巧,同时还回答了一些关于使用 [b]DataReader[/b] 的常见问题。
在访问相关 [b]Command[/b] 的任何输出参数之前,必须关闭 [b]DataReader[/b]。
完成读数据之后总是要关闭 [b]DataReader[/b]。如果使用 [b]Connection[/b] 只是用于返回 [b]DataReader[/b],那么关闭 [b]DataReader[/b] 之后立刻关闭它。 另外一个显式关闭 [b]Connection[/b] 的方法是把 [b]CommandBehavior.CloseConnection[/b] 传递给 [b]ExecuteReader[/b] 方法,以确保相关的连接在关闭 [b]DataReader[/b] 时被关闭。如果从一个方法返回 [b]DataReader[/b],而且不能控制 [b]DataReader[/b] 或相关连接的关闭,则这样做特别有用。
不能在层之间远程访问 [b]DataReader[/b]。[b]DataReader[/b] 是为已连接好的数据访问设计的。
当访问列数据时,使用类型化访问器,例如,[b]GetString[/b]、[b]GetInt32[/b] 等。这使您不用进行将 [b]GetValue[/b] 返回的 [b]Object[/b] 强制转换成特定类型所需的处理。
一个单一连接每次只能打开一个 [b]DataReader[/b]。在 ADO 中,如果打开一个单一连接,并且请求两个使用只进、只读游标的记录集,那么 ADO 会在游标生存期内隐式打开第二个、未池化的到数据存储区的连接,然后再隐式关闭该连接。对于 ADO.NET,“秘密”完成的动作很少。如果想在相同的数据存储区上同时打开两个 [b]DataReaders[/b],就必须显式创建两个连接,每个 [b]DataReader[/b] 一个。这是 ADO.NET 为池化连接的使用提供更多控制的一种方法。
默认情况下,[b]DataReader[/b] 每次 [b]Read[/b] 时都要把整行加载到内存。这允许在当前行内随机访问列。如果不需要这种随机访问,为了提高性能,就把 [b]CommandBehavior.SequentialAccess[/b] 传递给 [b]ExecuteReader[/b] 调用。这将 [b]DataReader[/b] 的默认行为更改为仅在请求时将数据加载到内存。注意,[b]CommandBehavior.SequentialAccess [/b]要求顺序访问返回的列。也就是说,一旦读过返回的列,就不能再读它的值了。
如果已经完成读取来自 [b]DataReader[/b] 的数据,但仍然有大量挂起的未读结果,就在调用 [b]DataReader[/b] 的 [b]Close[/b] 之前先调用 [b]Command[/b] 的 [b]Cancel[/b]。调用 [b]DataReader[/b] 的 [b]Close[/b] 会导致在关闭游标之前检索挂起的结果并清空流。调用 [b]Command[/b] 的 [b]Cancel[/b] 会放弃服务器上的结果,这样,[b]DataReader[/b] 在关闭的时候就不必读这些结果。如果要从 [b]Command[/b] 返回输出参数,还要调用 [b]Cancel[/b] 放弃它们。如果需要读取任何输出参数,不要调用 [b]Command[/b] 的 [b]Cancel[/b],只要调用 [b]DataReader[/b] 的 [b]Close[/b] 即可。
[b]二进制大对象 (BLOB)[/b] 用 [b]DataReader[/b] 检索二进制大对象 (BLOB) 时,应该把 [b]CommandBehavior.SequentialAccess[/b] 传递给 [b]ExecuteReader[/b] 方法调用。因为 [b]DataReader[/b] 的默认行为是每次 [b]Read[/b] 都把整行加载到内存,又因为 BLOB 值可能非常大,所以结果可能由于单个 BLOB 而使大量内存被用光。[b]SequentialAccess[/b] 将 [b]DataReader[/b] 的行为设置为只加载请求的数据。然后还可以使用 [b]GetBytes[/b] 或 [b]GetChars[/b] 控制每次加载多少数据。 记住,使用 [b]SequentialAccess[/b] 时,不能不按顺序访问 [b]DataReader[/b] 返回的不同字段。也就是说,如果查询返回三列,其中第三列是 BLOB,并且想访问前两列中的数据,就必须在访问 BLOB 数据之前先访问第一列的值,然后访问第二列的值。这是因为现在数据是顺序返回的,并且 [b]DataReader[/b] 一旦读过该数据,该数据就不再可用。 有关如何在 ADO.NET 中访问 BLOB 的详细描述,请参阅 [url=http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconobtainingblobvaluesfromdatabase.asp]Obtaining BLOB Values from a Database[/url]。
[url=http://ltp.cnblogs.com/admin/#top][img]http://ltp.cnblogs.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif[/img] [/url][url=http://ltp.cnblogs.com/admin/#top]返回页首[/url]
[url=http://msdn.microsoft.com/default.aspx?pull=gttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconadonetcommands.asp]Executing a Command[/url]。 [b]测试 Null[/b] 如果表(在数据库中)中的列允许为空,就不能测试参数值是否“等于”空。相反,需要写一个 WHERE 子句,测试列和参数是否都为空。下面的 SQL 语句返回一些行,它们的 LastName 列等于赋给 @LastName 参数的值,或者 LastName 列和 @LastName 参数都为空。
SELECT * FROM Customers
WHERE ((LastName = @LastName) OR (LastName IS NULL AND @LastName IS NULL))
[b]把 Null 作为参数值传递[/b] 对数据库的命令中,当把空值作为参数值发送时,不能使用 [b]null[/b](Visual Basic庐 .NET 中为 [b]Nothing[/b])。而需要使用 [b]DBNull.Value[/b]。例如:
'Visual Basic
Dim param As SqlParameter = New SqlParameter("@Name", SqlDbType.NVarChar, 20)
param.Value = DBNull.Value
//C#
SqlParameter param = new SqlParameter("@Name", SqlDbType.NVarChar, 20);
param.Value = DBNull.Value;
[b]执行事务[/b] ADO.NET 的事务模型已经更改。在 ADO 中,当调用 [b]StartTransaction[/b] 时,调用之后的任何更新操作都被视为是事务的一部分。但是,在 ADO.NET 中,当调用 [b]Connection.BeginTransaction[/b] 时,会返回一个 [b]Transaction[/b] 对象,需要把它与 [b]Command[/b] 的 [b]Transaction[/b] 属性联系起来。这种设计可以在一个单一连接上执行多个根事务。如果未将 [b]Command.Transaction[/b] 属性设置为一个针对相关的 [b]Connection[/b] 而启动的 [b]Transaction[/b],那么 [b]Command[/b] 就会失败并引发异常。 即将发布的 .NET 框架将使您可以在现有的分布式事务中手动登记。这对于对象池方案来说很理想;在该方案中,一个池对象打开一次连接,但是在多个独立的事务中都涉及到该对象。.NET 框架 1.0 发行版中这一功能并不可用。 有关事务的更多信息,请参阅 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconPerformingTransactions.asp]Performing Transactions[/url] 以及 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/dnbda/html/daag.asp].NET Data Access Architecture Guide[/url]。
[url=http://ltp.cnblogs.com/admin/#top][img]http://ltp.cnblogs.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif[/img] [/url][url=http://ltp.cnblogs.com/admin/#top]返回页首[/url]
[url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconConnectionPoolingForSQLServerNETDataProvider.asp]Connection Pooling for the SQL Server .NET Data Provider[/url] 和 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconConnectionPoolingForOLEDBNETDataProvider.asp]Connection Pooling for the OLE DB .NET Data Provider[/url]。 [b]用 DataAdapter 优化连接[/b] [b]DataAdapter[/b] 的 [b]Fill[/b] 和 [b]Update[/b] 方法在连接关闭的情况下自动打开为相关命令属性指定的连接。如果 [b]Fill[/b] 或 [b]Update[/b] 方法打开了连接,[b]Fill[/b] 或 [b]Update[/b] 将在操作完成的时候关闭它。为了获得最佳性能,仅在需要时将与数据库的连接保持为打开。同时,减少打开和关闭多操作连接的次数。 如果只执行单个的 [b]Fill[/b] 或 [b]Update[/b] 方法调用,建议允许 [b]Fill[/b] 或 [b]Update[/b] 方法隐式打开和关闭连接。如果对 [b]Fill[/b] 和/或 [b]Update[/b] 调用有很多,建议显式打开连接,调用 [b]Fill[/b] 和/或 [b]Update[/b],然后显式关闭连接。 另外,当执行事务时,显式地在开始事务之前打开连接,并在提交之后关闭连接。例如:
'Visual Basic
Public Sub RunSqlTransaction(da As SqlDataAdapter, myConnection As SqlConnection, ds As DataSet)
myConnection.Open()
Dim myTrans As SqlTransaction = myConnection.BeginTransaction()
myCommand.Transaction = myTrans
Try
da.Update(ds)
myTrans.Commit()
Console.WriteLine("Update successful.")
Catch e As Exception
Try
myTrans.Rollback()
Catch ex As SqlException
If Not myTrans.Connection Is Nothing Then
Console.WriteLine("An exception of type " & ex.GetType().ToString() & _
" was encountered while attempting to roll back the transaction.")
End If
End Try
Console.WriteLine("An exception of type " & e.GetType().ToString() & " was encountered.")
Console.WriteLine("Update failed.")
End Try
myConnection.Close()
End Sub
//C#
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();
}
[b]始终关闭 Connection 和 DataReader[/b] 完成对 [b]Connection[/b] 或 [b]DataReader[/b] 对象的使用后,总是显式地关闭它们。尽管垃圾回收最终会清除对象并因此释放连接和其他托管资源,但垃圾回收仅在需要时执行。因此,确保任何宝贵的资源被显式释放仍然是您的责任。并且,没有显式关闭的 [b]Connections[/b] 可能不会返回到池中。例如,一个超出作用范围却没有显式关闭的连接,只有当池大小达到最大并且连接仍然有效时,才会被返回到连接池中。 [b]注[/b] 不要在类的 [b]Finalize[/b] 方法中对 [b]Connection[/b]、[b]DataReader[/b] 或任何其他托管对象调用 [b]Close[/b] 或 [b]Dispose[/b]。最后完成的时候,仅释放类自己直接拥有的非托管资源。如果类没有任何非托管资源,就不要在类定义中包含 [b]Finalize[/b] 方法。 [b]在 C# 中使用 "Using" 语句[/b] 对于 C# 程序员来说,确保始终关闭 [b]Connection[/b] 和 [b]DataReader[/b] 对象的一个方便的方法就是使用 [b]using[/b] 语句。[b]using[/b] 语句在离开自己的作用范围时,会自动调用被“使用”的对象的 [b]Dispose[/b]。例如:
//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));
}
}
Using 语句不能用于 Microsoft庐 Visual Basic庐 .NET。 [b]避免访问 OleDbConnection.State 属性[/b] 如果连接已经打开,[b]OleDbConnection.State[/b] 属性会对 [b]DBPROP_CONNECTIONSTATUS[/b] 属性的 [b]DATASOURCEINFO [/b]属性集执行本地 OLE DB 调用 [b]IDBProperties.GetProperties[/b],这可能会导致对数据源的往返行程。也就是说,检查 [b]State[/b] 属性的代价可能很高。所以仅在需要时检查 [b]State[/b] 属性。如果需要经常检查该属性,监听 [b]OleDbConnection[/b] 的 [b]StateChange[/b] 事件可能会使应用程序的性能好一些。有关 [b]StateChange[/b] 事件的详细信息,请参阅 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconWorkingWithConnectionEvents.asp]Working with Connection Events[/url]。
[url=http://ltp.cnblogs.com/admin/#top][img]http://ltp.cnblogs.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif[/img] [/url][url=http://ltp.cnblogs.com/admin/#top]返回页首[/url]
[url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconXMLDataSet.asp]XML and the DataSet[/url]。 [b]架构推断[/b] 从 XML 文件加载 [b]DataSet[/b] 时,可以从 XSD 架构加载 [b]DataSet[/b] 架构,或者在加载数据前预定义表和列。如果没有可用的 XSD 架构,而且不知道为 XML 文件的内容定义哪些表和列,就可以在 XML 文档结构的基础上对架构进行推断。 架构推断作为迁移工具很有用,但应只限于设计阶段应用程序,这是由于推断处理有如下限制。
对架构的推断会引入影响应用程序性能的附加处理。
所有推断列的类型都是字符串。
推断处理不具有确定性。也就是说,它是基于 XML 文件内容的,而不是预定的架构。因此,对于两个预定架构相同的 XML 文件,由于它们的内容不同,结果得到两个完全不同的推断架构。
有关更多信息,请参阅 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconInferringDataSetRelationalStructureFromXML.asp]Inferring DataSet Relational Structure from XML[/url]。 [b]用于 XML 查询的 SQL Server[/b] 如果正从 SQL Server 2000 FOR XML 返回查询结果,可以让用于 SQL Server 的 .NET 框架数据提供程序使用 [b]SqlCommand.ExecuteXmlReader[/b] 方法直接创建一个 [b]XmlReader[/b]。 [b]SQLXML 托管类[/b] .NET 框架中有一些类,公开用于 SQL Server 2000 的 XML 的功能。这些类可在 [b]Microsoft.Data.SqlXml [/b]命名空间中找到,它们添加了执行 XPath 查询和 XML 模板文件以及把 XSLT 转换应用到数据的能力。 SQLXML 托管类包含在用于 Microsoft SQL Server 2000 的 XML (SQLXML 2.0) 发行版中,可从 [url=http://www.microsoft.com/downloads/release.asp?ReleaseID=33055]XML for Microsoft SQL Server 2000 Web Release 2 (SQLXML 2.0)[/url] ??μ?。
[url=http://ltp.cnblogs.com/admin/#top][img]http://ltp.cnblogs.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif[/img] [/url][url=http://ltp.cnblogs.com/admin/#top]返回页首[/url]
[url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconRetrievingIdentityOrAutonumberValues.asp]Retrieving Identity or AutoNumber Values[/url]。 [b]检查开放式并发冲突[/b] 按照设计,由于 [b]DataSet[/b] 是与数据源断开的,所以,当多个客户端在数据源上按照开放式并发模型更新数据时,需要确保应用程序避免冲突。 在测试开放式并发冲突时有几项技术。一项技术涉及在表中包含时间戳列。另外一项技术是,验证一行中所有列的原始值是否仍然与通过在 SQL 语句中使用 WHERE 子句进行测试时在数据库中找到的值相匹配。 有关包含代码示例的该主题的详细讨论,请参阅 [url=http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconOptimisticConcurrency.asp]Optimistic Concurrency[/url]。 [b]多线程编程[/b] ADO.NET 对性能、吞吐量和可伸缩性进行优化。因此,ADO.NET 对象不锁定资源,并且必须只用于单线程。一个例外是 [b]DataSet[/b],它对多个阅读器是线程安全的。但是,在写的时候需要把 [b]DataSet[/b] 锁定。 [b]仅在需要的时候才用 COM Interop 访问 ADO[/b] ADO.NET 的设计目的是成为许多应用程序的最佳解决方案。但是,有些应用程序需要只有使用 ADO 对象才有的功能,例如,ADO 多维 (ADOMD)。在这些情况下,应用程序可以用 COM Interop 访问 ADO。注意使用 COM Interop 访问具有 ADO 的数据会导致性能降低。在设计应用程序时,首先在实现用 COM Interop 访问 ADO 的设计之前,先确定 ADO.NET 是否满足设计需求。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部