ASP.NET3.5核心编程学习笔记14:DataAdapter_炮土狼烟_

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据适配器
数据适配器对象充当数据源与DataSet对象间的双向桥梁。

DataSet是一种非连接的数据容器,适配器负责对它进行填充,并能把它的数据提交给特定的数据源。

命令与数据适配器最大的不同在于获取数据后的返回方式。

查询命令能返回一种只读、只进的游标—数据读取器。

数据适配器能执行数据访问,获取所有数据,并将其打包在内存容器中—DataSet或DataTable。

其实,数据适配器是一种额外的抽象层,构建于命令/数据读取器对之上。

数据适配器在内部会使用命令进行查询,使用数据读取器遍历所有记录,并填充给用户的DataSet。

SqlDataAdapter类
数据适配器类继承于DbDataAdapter类,并实现了IDbDataAdapter和ICloneable接口。

SqlDataAdapter类的属性见下表:
数据适配器是一条双向信道,能够将数据源数据读取到内存表中,也能够将内存中的数据写回数据源中。

IDbAdapter接口的xxxCommand成员用于在更新操作期间控制内存数据写入数据库的方式。

SelectCommand有些特殊,它不仅在批量更新中发挥着作用,还是填充操作必不可少的成员。

一旦数据被加载到内存中,.NET程序便可对其执行非连接的客户端更新。

批量更新是一种由客户端应用程序触发的数据提供程序过程,会将内存中所有挂起的更改应用到数据源中。

在这个过程的执行期间,需要一套针对特定数据库管理系统的命令执行3项基本的操作:插入、更新、删除。

InsertCommand、UpdateCommand、DeleteCommand属性存储的SqlCommand对象正是分别针对这些操作的命令。

批量更新包括一系列通过数据适配器顺序提交给数据库的命令。

作为开发者,我们只需一条命令便可触发批量更新。

从概念上应记住,批量更新不同于通过单条命令提交的一系列查询,也不意味着将批量的命令和数据统统移动到DBMS中,并在那执行。

批量更新功能强大,但并不适用于应用程序。

问题在于Web应用程序工作在无状态协议上。

这样,如果要使整个框架正常运行,我们要将内存表缓存到会话中,而这不是所有应用程序都能承受的。

此外还应注意,使用批量更新可减少大量的编码工作,并可对其进行配置来处理复杂的更新。

但在 1.x中,由于每次操作都使用其自己的命令,因而使用批量更新并无多少性能优势。


2.0开始,我们可以通过新的UpdateBatchSize属性将多个更新操作集中在一条命令中。

SqlDataAdapter的方法见下表:
数据适配器对象使用SelectCommand属性从数据源获取模式和数据。

与SelectCommand关联的连接对象不必手动打开。

如果该连接在读取执行前处于关闭状态,那么在获取数据时它会被自动打开,读取完毕后自动关闭。

如果连接已被手动打开,则会一直保持该状态,直到手动关闭。

数据适配器对象会使用Fill方法将通过查询获得的数据填充到内存对象中。

这个内存结构为DataSet或DataTable对象。

填充DataSet对象就是填充其中的表。

数据适配器可以为程序生成的每个结果集创建一张表,表的映射代码决定其方式(如果某个表已存在,则会被更新)。

将结果集映射到个上的过程分为两个阶段,分别为表映射和列映射。

第一阶段中,数据适配器会确定DataTable的名称,该对象包含当前结果集记录。

每个DataTable被指定的默认名称可由程序员随意更改。

DataTable的默认名称取决于所调用的Fill方法的签名,例如下面的示例:DataSet ds =new DataSet();
adapter.Fill(ds);
adapter.Fill(ds, “MyTable”);
在第一个调用中,由查询生成的第一个结果集的名词默认为Table,如果该查询生成了多个结果集,其他的表会依次在该默认名称后面追加索引号,如Table1、Table2等。

对于第二个调用,第一个结果集为MyTable,其他的表依次为
MyTable1、MyTable2等。

有两种方法更改表的名称:一是在DataSet被填充后;二是创建表映射。

对于后者,我们可以通过设置将其他名称映射到要更改名称的表上。

为在数据适配器上定义表映射,要用于TableMappings属性。

我们还可以使用Fill方法来填充DataTable,在这种情况下,只会使用第一个结果集,并且只会执行一种映射,即列映射。

DataTable dt =new DataTable();
adapter.Fill(dt);
加载设置
在 2.0和更高版本中,在填充操作执行期间,可用FillLoadOption属性指定数据加载到各种数据表的方式。

FillLoadOption属性可接受LoadOption枚举
值。

下表列出了各种取值的含义:
对于每种情况,仅当输入行的主键与现有行的主键匹配时,所指定的行为才会生效。

OverwriteChanges可满足我们用新数据对表进行初始化的需要。

PreserveChanges适合于对现有内存数据与当前数据库状态进行同步。

如果要更新DataSet中代表数据库读取的原始数据的值,可使用Upsert。

内存中的行要维护两种值:当前值和原始值。

当前值为读取单元格时得到的值,而原始值是最后一次提交时存储在单元格中的值。

向一个新插入的行赋值时,设置的是当前值,原始值得为空(null)。

被赋予的值在提交给数据库后才能真正在数据库中生效。

为提交某行,可调用AcceptChanges方法,调用该方法后,当前值会被复制并覆盖原始值,该行的状态变为未更改,不再有挂起的更改。

提交某行(DataRow类)的更改给原始版数据:
row.AcceptChanges();
读取某行的当前值:
row[“firstname”].ToString();
读取某行的原始值:
row[“firstname”, DataRowVersion.Original].ToString();
表映射机制
对于查询生成的结果集,.NET数据提供程序会为其赋予一个默认的名称。

适配器会在TableMappings查找与正在读取的结果集默认名称匹配的数据项。

如果找到匹配项,数据适配器会读取被映射的名称。

接着,通过在映射中指定的名称,它会试图确定DataSet中DataTable对象的位置。

TableMappings属性代表DataTableMappingCollection类型的集合对象,每个数据项为DataTableMapping对象,它代表一对名称:源表名称和内存表名称。

示例代码:
DataSet ds =new DataSet();
DataTableMapping dtm1, dtm2, dtm3;
dtm1 = adapter.TableMappings.Add(“Table”, “Employees”);
dtm2 = adapter.TableMappings.Add(“Table1”, “Products”);
dtm3 = adapter.TableMappings.Add(“Table2”, “Orders”);
adapter.Fill(ds);
表映射的数据没有限制,且映射的总数与期望的结果集数量无关。

如果只是想为DataSet表赋予一个容易记忆的名称,可使用这样的代码:DataSet ds =new DataSet();
adapter.Fill(ds);
ds.Tables[“Table”].TableName = “Employees”;
ds.Tables[“Table1”].TableName = “Products”;
映射机制还有另外一点,即列映射。

列映射用于在结果集的列与被映射的DataTable对象间建立链接。

列映射存储在ColumnMappings集合属性中,其类型为DataTableMapping。

示例代码:
DataSet ds =new DataSet();
DataTableMapping dtm1;
dtm1 = adapter.TableMappings.Add(“Table”, “Employees”);
dtm1.ColumnMappings.Add(“employeeid”, “ID”);
dtm1.ColumnMappings.Add(“firstname”, “Name”);
dtm1.ColumnMappings.Add(“lastname”, “FamilyName”);
adapter.Fill(ds);
当适配器无法找到表或列映射,或者说无法找到所需的DataTable或DataColumn时,会抛出一种轻型的异常。

当数据适配器在收集要填充DataSet的数据时,缺少映射操作会在两种情况下执行,分别为:无法在TableMappings集合中找到默认的名称时;ColumnMappings集合中某个列名不存在时。

为处理这两个异常,要通过MissingMappingAction属性对数据适配器的行为进行定义。

该属性是MissingMappingAction枚举类型,其定义见下表:
在表映射阶段,如果无法确定DataSet中表的名称或DataSet表不包含期望映射名称的列,则需要执行缺少模式操作。

MissingSchemaAction属性用于指定缺少表模式时要执行的操作。

该属性是MissingSchemaAction枚举类型,其定义见下表:
MissingMappingAction与MissingSchemaAction不会有真正的异常开销,但仍影响代码的效率。

如果正好需要以某种固定的模式重复填充某个空的DataSet,则可以
使用预填充模式信息的DataSet对象。

FillSchema方法能确保所有需要的对象都事先创建。

DataTable[] FillSchema(DataSet ds, SchemaType mappingMode);
该方法接受一个DataSet,其中添加了与适配器关联查询命令所需的表。

该方法会返回创建的所有DataTable对象(其中仅包含模式,而没有数据)。

SchemaType是枚举类型,其取值见下表:
批量更新
更新过程中的冲突检测可能会想起相当大的开销,甚至会使批量更新方案的优势大大降低,在数据竞争程度较低的环境下,批量更新才比较有效。

要将客户端更改提交给服务器,可使用数据适配器的Update方法。

数据只能以表为单位提交。

如果未指定表名,则使用默认名称—Table。

如:
adapter.Update(ds, “MyTable”);
Update方法能为特定表中被插入、更新、删除的行逐一准备并执行特殊生成的Insert、Update、Delete语句。

该方法返回一个整数表示被成功更新的行数。

如果ContinueUpdateOnError设置为true,则某行在更新时出现错误后,更新仍会继续,直到所有行都处理完毕。

DataSet中被成功更新的行会被提交并被标记为未更改。

命令生成器
在中,Insert、Update、Delete命令可以自动生成并暴露给数据适配器。

命令生成器对象可以完成这些工作,但它不能适用于所有情况,命令的自动生成仅能在特定环境下执行。

具体来说,如果表是以多表联接获得的,或表中含有通过计算(或总计)得到的列,命令生成器则无法生成任何命令。

仅当适配器执行Update方法时,命令生成器才能发挥作用。

那么命令生成器如何为泛化的表生成更新命令呢?这就是SelectCommand属性所要解决的问题。

为了生成各种更新命令,命令生成器会使用SelectCommand来获取所需的元数据。

我们必须将SelectCommand设置为包含主键列名称及要操纵列名称的查询字符串,只有这些列会被更新,待更新或删除的行用主键来标识。

数据适配器要通过命令生成器的构造函数与生成器进行关联。

如下所示:SqlCommand cmd =new SqlCommand();
mandText = “Select employeeid, lastname From employees”;
cmd.Connection = conn;
adapter.SelectCommand = cmd;
SqlCommandBuilder builder =new SqlCommandBuilder(adapter);
adapter.InsertCommand = builder.GetInsertCommand();
adapter.DeleteCommand = builder.GetDeleteCommand();
adapter.UpdateCommand = builder.GetUpdateCommand();
生成器会请求元数据,并在首次请求时生成并缓存命令。

每种命令可通过相应的方法获取,这些方法为GetInsertCommand、GetUpdateCommand、GetDeleteCommand。

注意,命令生成器不会自动设置数据适配器的相应命令属性,必须手动设置adapter的相关命令属性。

相关文档
最新文档