ADO.NET框架数据提供程序
.NET.NET框架数据提供程序?
为了使您的应用程序获得最佳性能,请使用最适合您的数据源的.NET框架数据提供程序。有许多数据提供程序可供您的应用程序选用。
ODBC.NET
数据提供程序可在Microsoft.Data.ODBC命名空间中找到,它的体系结构与用于
SQLServer和
OLE DB的
.NET数据提供程序相同。ODBC .NET数据提供程序遵循命名约定
-以“ODBC”为前缀(例如,
OdbcConnection),并使用标准ODBC连接字符串。
当使用DataSet时,经常会利用
DataAdapter(也可能是
CommandBuilder)与数据源进行交互。当使用
DataSet时,也可以利用
DataView对
DataSet中的数据应用排序和筛选。也可以从
DataSet继承,创建强类型
DataSet,用于将表、行和列作为强类型对象属性公开。
下列主题包括的信息涉及:使用DataSet或
DataReader的最佳时机、如何优化访问它们所包含数据、以及如何优化使用
DataAdapter(包括
CommandBuilder)和
DataView的技巧。
DataSetDataSet的好处
DataSet
的另一个好处是可被继承以创建一个强类型DataSet。强类型
DataSet的好处包括设计
时类型检查,以及Microsoft Visual Studio.NET用于强类型
DataSet语句结束所带来的好处。修改了
DataSet的架构或关系结构后,就可以创建一个强类型
DataSet,将行和列作为对象的属性公开,而不是作为集合中的项公开。例如,不公开客户表中行的姓名列,而公开Customer对象的
Name属性。类型化
DataSet从
DataSet类派生,因此不会牺牲
DataSet的任何功能。也就是说,类型化
DataSet仍能远程访问,并作为数据绑定控件(例如
DataGrid)的数据源提供。如果架构事先不可知,仍能受益于通用
DataSet的功能,但却不能受益于强类型
DataSet的附加功能。
如果想用服务器上的更新值刷新DataSet中的值,就使用
DataAdapter.Fill。如果有在
DataTable上定义的主键,
DataAdapter.Fill会根据主键进行新行匹配,并且当更改到现有行时应用服务器上的值。即使刷新之前修改了这些数据,刷新行的
RowState仍被设置为
Unchanged。注意,如果没有为
DataTable定义主键,
DataAdapter.Fill就用可能重复的主键值添加新行。
如果想用来自服务器的当前值刷新表,并同时保留对表中的行所做的任何更改,必须首先用DataAdapter.Fill填充表,并填充一个新的
DataTable,然后用
preserveChanges值
true将
DataTable合并到
DataSet之中。
如果创建了DataView,并且修改了
Sort、
RowFilter或
RowStateFilter属性,
DataView就会为基础
DataTable中的数据建立索引。创建
DataView对象时,要使用
DataView构造函数,它用
Sort、
RowFilter和
RowStateFilter值作为构造函数参数(与基础
DataTable一起)。结果是创建了一次索引。创建一个“空”
DataView并随后设置
Sort、
RowFilter或
RowStateFilter属性,会导致索引至少创建两次。
ADO.NET
startRecord和
maxRecords值的
DataAdapter.Fill重载。当以这种方式填充
DataSet时,只有
maxRecords参数(从
startRecord参数标识的记录开始)指定的记录数量用于填充
DataSet,但无论如何总是返回完整的查询。这就会引起不必要的处理,用于读取“不需要的”记录;而且为了返回附加记录,会耗尽不必要的服务器资源。
2) SQL语句,将TOP谓词和嵌入式
SELECT语句的使用结合在一起。此技术并不依赖于存在一种可唯一标识每一行的办法。使用这项技术的第一步是将所需页的数量与
页大小相乘。然后将结果传递给SQL Query的
TOP谓词,该查询以升序排列。再将此查询嵌入到另一个查询中,后者从降序排列的嵌入式查询结果中选择TOP页大小。实质上,返回的是嵌入式查询的最后一页。例如,要返回查询结果的第三页(
页大小是10),应该书写如下所示的命令:
SELECT TOP 10 * FROM (SELECT TOP 30 * FROMCustomers ORDER BY Id ASC) AS Table1 ORDER BY Id DESC
1) 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。
下面是一些使用DataReader获得最佳性能的技巧,同时还回答了一些关于使用
DataReader的常见问题。
1) 在访问相关
Command的任何输出参数之前,必须关闭
DataReader。
2) 完成读数
据之后总是要关闭
DataReader。如果使用
Connection只是用于返回
DataReader,那么关闭
DataReader之后立刻关闭它。
另外一个显式关闭Connection的方法是将
CommandBehavior.CloseConnection传递给
ExecuteReader方法,以确保相关的连接在关闭
DataReader时被关闭。如果从一个方法返回
DataReader,而且不能控制
DataReader或相关连接的关闭,则这样做特别有用。
1) 不能在层之间远程访问
DataReader。
DataReader是为已连接好的数据访问设计的。
2) 当访问列数据时,使用类型
化访问器,例如,
GetString、
GetInt32等。这使您不用进行将
GetValue返回的
Object强制转换成特定类型所需的处理。
3) 一个单一连接每次只能打开一个
DataReader。在ADO中,如果打开一个单一连接,并且请求两个使用只进、只读游标的记录集,那么
ADO会在游标生存期内隐式打开第二个、未池化的到数据存储区的连接,然后再隐式关闭该连接。对于
ADO.NET,“秘密”完成的动作很少。如果想在相同的数据存储区上同时打开两个
DataReaders,就必须显
式创建两个连接,每个
DataReader一个。这是
ADO.NET为池化连接的使用提供更多控制的一种方法。
4) 默认情况下,
DataReader每次Read时都要将整行加载到内存。这允许在当前行内随机访问列。如果不需要这种随机访问,为了提高性能,就将
CommandBehavior.SequentialAccess传递给
ExecuteReader调用。这将
DataReader的默认行为更改为仅在请求时将数据加载到内存。注意,
CommandBehavior.SequentialAccess要求顺序访问返回的列。也就是说,一旦读过返回的列,就不能再读它的值了。
5) 如果已经完成读取来自
DataReader的数据,但仍然有大量挂起的未读结果,就在调用
DataReader的
Close之前先调用Command的
Cancel。调用
DataReader的
Close会导致在关闭游标之前检索挂起的结果并清空流。调用Command的
Cancel会放弃服务器上的结果,这样,
DataReader在关闭的时候就不必读这些结果。如果要从Command返回输出参数,还要调用
Cancel放弃它们。如果需要读取任何输出参数,不要调用Command的
Cancel,只要调用
DataReader的
Close即可。
<SPANSTYLE='FONT-SIZE:12.0PT;"done">大对象(BLOB)
用DataReader检索二进制
大对象(BLOB)时,应该将
CommandBehavior.SequentialAccess传递给
ExecuteReader方法调用。因为
DataReader的默认行为是每次
Read都将整行加载到内存,又因为BLOB值可能非常大,所以结果可能由于单个
BLOB而使大量内存被用光。
SequentialAccess将
DataReader的行为设置为只加载请求的数据。然后还可以使用
GetBytes或
GetChars控制每次加载多少数据。
记住,使用SequentialAccess时,不能不按顺序访问
DataReader返回的不同字段。也就是说,如果查询返回三列,其中第三列是BLOB,并且想访问前两列中的数据,就必须在访问
BLOB数据之前先访问第一列的值,然后访问第二列的值。这是因为现在数据是顺序返回的,并且
DataReader一旦读过该数据,该数据就不再可用。
| |