40
数数数数数 SqlDataAdapter 数 数数数数数数 DataSet 数数数 SQL Server 数数数数 数数数数数数数 数数数数数数数 一一。 数数数数数数 数数数数 System.Data.SqlClient.SqlDataAdapter SqlDataAdapter 数 DataSet 数 SQL Server 数数数数数数 数数数数数 数数数数SqlDataAdapter 数数数数数数数数数数数 Transact-SQL 数数数数 Fill 数数数数 DataSet 数数数数数数数数数数数数数数 Update 数数数数数数 数数数数数数数数 DataSet 数数数数 数数数数数 数数数 )一。 SqlConnection conn = new SqlConnection(connection); SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand = new SqlCommand(query, conn); DataSet dataset; adapter.Fill(dataset);

数据适配器 - SqlDataAdapter 类

  • Upload
    nicole

  • View
    150

  • Download
    0

Embed Size (px)

DESCRIPTION

数据适配器 - SqlDataAdapter 类. 表示用于填充 DataSet 和更新 SQL Server 数据库的一组数据命令和一个数据库连接。不能继承此类。命名空间 System.Data.SqlClient.SqlDataAdapter - PowerPoint PPT Presentation

Citation preview

Page 1: 数据适配器 - SqlDataAdapter 类

数据适配器- SqlDataAdapter 类

• 表示用于填充 DataSet 和更新 SQL Server 数据库的一组数据命令和一个数据库连接。不能继承此类。命名空间 System.Data.SqlClient.SqlDataAdapter

• SqlDataAdapter 是 DataSet 和 SQL Server 之间的桥接器,用于检索和保存数据。 SqlDataAdapter 通过对数据源使用适当的 Transact-SQL 语句映射 Fill (它可更改 DataSet 中的数据以匹配数据源中的数据)和 Update (它可更改数据源中的数据以匹配 DataSet 中的数据)来提供这一桥接。

例:SqlConnection conn = new SqlConnection(connection);

SqlDataAdapter adapter = new SqlDataAdapter();

adapter.SelectCommand = new SqlCommand(query, conn);

DataSet dataset;

adapter.Fill(dataset);

Page 2: 数据适配器 - SqlDataAdapter 类

数据适配器- SqlDataAdapter 类

• 当 SqlDataAdapter 填充 DataSet 时,它将为返回的数据创建必要的表和列(如果它们尚不存在)。但是,除非 MissingSchemaAction 属性设置为 AddWithKey ,否则这个隐式创建的架构中就将不包括主键信息。也可以在使用 FillSchema 为数据集填充数据前,让 SqlDataAdapter 创建 DataSet 的架构(包括主键信息)。

• SqlDataAdapter 与 SqlConnection 和 SqlCommand 一起使用,以便在连接到 Microsoft SQL Server 数据库时提高性能。

• SqlDataAdapter 还包括 SelectCommand 、 InsertCommand 、 DeleteCommand 、 UpdateCommand 和 TableMappings 属性,使数据的加载和更新更加方便。

• 当创建 SqlDataAdapter 的实例时,读 / 写属性将被设置为初始值。有关这些值的列表,参见 SqlDataAdapter 构造函数。

Page 3: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 构造函数• public SqlDataAdapter();

例:

SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

SqlDataAdapter custDA = new SqlDataAdapter();

custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

Page 4: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 构造函数

• public SqlDataAdapter(SqlCommand) :将指定的 SqlCommand 作为 SelectCommand 属性,初始化 SqlDataAdapter 类的新实例

例:

SqlConnection nwindConn = new SqlConnection("Data Source=localhost; Integrated Security=SSPI;Initial Catalog=northwind");

SqlCommand selectCMD = new SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);

SqlDataAdapter custDA = new SqlDataAdapter(selectCMD); custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

Page 5: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 构造函数• public SqlDataAdapter(string, SqlConnection) :使用 SelectCom

mand 和 SqlConnection 对象初始化 SqlDataAdapter 类的新实例

例:SqlConnection custConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial

Catalog=northwind");

SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", custConn);

custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

Page 6: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 构造函数• public SqlDataAdapter(string, string) :用 SelectComman

d 和一个连接字符串初始化 SqlDataAdapter 类的新实例

例:

SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

SqlConnection custConn = custDA.SelectCommand.Connection;

custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

Page 7: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• 当创建 SqlDataAdapter 的实例时,下面的读 / 写属性将设置为以下初始值Properties

MissingMappingAction -确定传入数据没有匹配的表或列时需要执行的操作值: Passthrough -创建源列或源表,并使用其原始名称将其添加到 DataSet

(初始值)Error -如果缺少指定的列映射,则生成 InvalidOperationException

Ignore -忽略没有映射的列或表。返回空引用( Visual Basic 中为 Nothing )。

MissingSchemaAction -确定现有 DataSet 架构与传入数据不匹配时需要执行的操作值: MissingSchemaAction.Add -添加必需的列以完成架构(初始值)

AddWithKey -添加必需的列和主键信息以完成架构Error -如果缺少指定的列映射,则生成 InvalidOperationException

Ignore -忽略额外列

可以通过单独调用属性来更改任何这些属性的值

Page 8: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• AcceptChangesDuringFill (从 DataAdapter 继承)获取或

设置一个值,该值指示在任何 Fill 操作过程中,在将 AcceptChanges 添加到 DataTable 之后是否针对 DataRow 调用它,如果在 DataRow 上调用 AcceptChanges ,则为 true ;否则为 false 。默认值为 true

• Container (从 Component 继承)获取 IContainer ,它包含 Component 。如果 Component 未在 IContainer 中封装,则该值为空引用。 IContainer 提供容器的功能。容器是在逻辑上包含零个或更多个组件的对象。容器是封装和跟踪零个或更多个组件的对象。在此上下文中,包容是指逻辑包容,而不是直观包容。可以在多种方案下使用组件和容器,包括可视化方案和非可视化方案。对实施者的说明 :   要成为容器,类必须实现 IContainer 接口,该接口支持添加、移除和检索组件的方法

Page 9: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• TableMappings (从 DataAdapter 继承)获取一个集合,它提供源表和 DataTabl

e 之间的主映射,默认值是一个空集合。当协调更改时, DataAdapter 使用 DataTableMappingCollection 集合将数据源使用的列名与 DataSet 使用的列名关联起来

public void ShowTableMappings() { // ... // create myDataAdapter // ... myDataAdapter.TableMappings.Add("Categories","DataCategories"); myDataAdapter.TableMappings.Add("Orders","DataOrders"); myDataAdapter.TableMappings.Add("Products","DataProducts"); string myMessage = "Table Mappings:\n"; for(int i=0;i < myDataAdapter.TableMappings.Count;i++) { myMessage += i.ToString() + " " + myDataAdapter.TableMappings[i].ToString() + "\n"; } MessageBox.Show(myMessage);}

Page 10: 数据适配器 - SqlDataAdapter 类

DataTable 和 DataColumn 映射

• DataAdapter 在其 TableMappings 属性中包含零个或更多个 DataTableMapping 对象的集合。 DataTableMapping 提供对数据源的查询所返回的数据与 DataTable 之间的主映射。 DataTableMapping 名称可以代替 DataTable 名称传递到 DataAdapter 的 Fill 方法。以下示例为 MyAuthors 表创建名为 AuthorsMapping 的 DataTableMapping 。

workAdapter.TableMappings.Add("AuthorsMapping", "MyAuthors");

• DataTableMapping 使得能够使用 DataTable 中与数据库中的列名不同的列名。当该表被更新时, DataAdapter 将使用此映射来匹配列。

• 如果在调用 DataAdapter 的 Fill 或 Update 方法时未指定 TableName 或 DataTableMapping 名称, DataAdapter 将查找名为“ Table” 的 DataTableMapping 。如果 DataTableMapping 不存在, DataTable 的 TableName 将为“ Table” 。可以通过创建名为“ Table” 的 DataTableMapping 来指定默认的 DataTableMapping 。

Page 11: 数据适配器 - SqlDataAdapter 类

DataTable 和 DataColumn 映射• 以下代码示例创建一个 DataTableMapping (从 System.Data.Com

mon 命名空间)并通过将其命名为“ Table” 来使其成为指定 DataAdapter 的默认映射。然后,该示例将查询结果中第一个表( Northwind 数据库的 Customers 表)中的列映射到 DataSet 的 Northwind Customers 表中的一组更为用户友好的名称。对于未映射的列,将使用数据源中的列名称。

DataTableMapping custMap = custDA.TableMappings.Add("Table", "NorthwindCustomers");

custMap.ColumnMappings.Add( "CompanyName", "Company"); custMap.ColumnMappings.Add( "ContactName", "Contact");custMap.ColumnMappings.Add( "PostalCode", "ZIPCode");custDA.Fill(custDS);

• 在更为复杂的情况下,可能会决定需要使用相同的 DataAdapter 来支持为不同的表加载不同的映射。若要完成此任务,只需添加附加的 DataTableMapping 对象。

Page 12: 数据适配器 - SqlDataAdapter 类

DataTable 和 DataColumn 映射• 当 Fill 方法以 DataSet 实例和 DataTableMapping 名称的形式进行传递时,如果存在具有该名称的映射,则使用该映射;否则将使用具有该名称的 DataTable 。

• 以下示例创建一个名称为 Customers 而 DataTable 名称为 BizTalkSchema 的 DataTableMapping 。然后,该示例将 SELECT 语句所返回的行映射到 BizTalkSchema DataTable 。

ITableMapping bizMap = custDA.TableMappings.Add("Customers", "BizTalkSchema");bizMap.ColumnMappings.Add( "CustomerID", "ClientID");bizMap.ColumnMappings.Add( "CompanyName", "ClientName");bizMap.ColumnMappings.Add( "ContactName", "Contact");bizMap.ColumnMappings.Add( "PostalCode", "ZIP");custDA.Fill(custDS, "Customers");

注意:如果没有为列映射提供源列名称或者没有为表映射提供源表名称,则将自动生成默认名称。如果没有为列映射提供源列,则将给列映射提供递增的默认名称 SourceColumnN,这些名称从“ SourceColumn1”开始。如果没有为表映射提供源表名称,则将给该表映射提供递增的默认名称 SourceTableN,这些名称从“ SourceTable1”开始。 建议在为列映射提供源列名称时避免使用“ SourceColumnN” 命名约定,在为表映射提供源表名称时避免使用“ SourceTableN” 命名约定,因为所提供的名称可能会与 ColumnMappingCollection 中现有的默认列映射名称或 DataTableMappingCollection 中的表映射名称发生冲突。如果提供的名称已经存在,将引发异常。

Page 13: 数据适配器 - SqlDataAdapter 类

DataTable 和 DataColumn 映射多个结果集:

• 如果 SelectCommand 返回多个表, Fill 将自动使用递增值为 DataSet 中的表生成表名称,这些表名称从指定表名称开始,并以 TableNameN 格式(从“ TableName1”开始)继续。可以使用表映射将自动生成的表名称映射到要为 DataSet 中的表指定的名称。例如,对于返回两个表( Customers 和 Orders )的 SelectCommand ,可对 Fill 发出以下调用。

custDA.Fill(custDS, "Customers")

• 在 DataSet 中创建了两个表: Customers 和 Customers1 。可以使用表映射来确保第二个表名为 Orders 而不是 Customers1 。若要完成此任务,请将 Customers1 的源表映射到 DataSet 表 Orders ,如以下示例所示。

custDA.TableMappings.Add("Customers1", "Orders")

custDA.Fill(custDS, "Customers")

Page 14: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• SelectCommand 获取或设置一个 Transact-SQL 语句或存储过程,用于在

数据源中选择记录。

下面的实例将创建一个 SqlDataAdapter 并设置 SelectCommand 属性。假定已经创建一个 SqlConnection 对象

public static SqlDataAdapter CreateCustomerAdapter(SqlConnection conn){ SqlDataAdapter da = new SqlDataAdapter(); SqlCommand cmd; // Create the SelectCommand. cmd = new SqlCommand("SELECT * FROM Customers " + "WHERE Country = @Country AND City = @City", conn); cmd.Parameters.Add("@Country", SqlDbType.NVarChar, 15); cmd.Parameters.Add("@City", SqlDbType.NVarChar, 15); da.SelectCommand = cmd;return da;}

Page 15: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• DeleteCommand 获取或设置一个 Transact-SQL 语句或存储过程,以从数据

集删除记录。在 Update 过程中,如果未设置此属性而且 DataSet 中存在主键信息,则在设置 SelectCommand 属性并使用 SqlCommandBuilder 的情况下,可以自动生成 DeleteCommand 。

面的实例创建一个 SqlDataAdapter 并设置 DeleteCommand 属性。假定已经创建一个 SqlConnection 对象

public static SqlDataAdapter CreateCustomerAdapter(SqlConnection conn)

{

SqlDataAdapter da = new SqlDataAdapter();

SqlCommand cmd;

SqlParameter parm;

// Create the DeleteCommand.

cmd = new SqlCommand("DELETE FROM Customers WHERE CustomerID = @CustomerID", conn);

parm = cmd.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");

parm.SourceVersion = DataRowVersion.Original;

da.DeleteCommand = cmd;

return da;

}

Page 16: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• InsertCommand 获取或设置一个 Transact-SQL 语句或存储过程,以在数据源

中插入新记录。在 Update 过程中,如果未设置此属性而且 DataSet 中包含主键信息,则在设置 SelectCommand 属性并使用 SqlCommandBuilder 的情况下,可以自动生成 InsertCommand 。

下面的实例将创建一个 SqlDataAdapter 并设置 SelectCommand 和 InsertCommand 属性。假定已经创建一个 SqlConnection 对象

public static SqlDataAdapter CreateCustomerAdapter(SqlConnection conn){ SqlDataAdapter da = new SqlDataAdapter(); SqlCommand cmd;// Create the InsertCommand. cmd = new SqlCommand("INSERT INTO Customers (CustomerID, CompanyName) " + "VALUES (@CustomerID, @CompanyName)", conn); cmd.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID"); cmd.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40, "CompanyName"); da.InsertCommand = cmd; return da;}

Page 17: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• UpdateCommand -获取或设置一个 Transact-SQL 语句或存储过程,用于更新数据源

中的记录。在 Update 过程中,如果未设置此属性而且 DataSet 中包含主键信息,则在设置 SelectCommand 属性并使用 SqlCommandBuilder 的情况下,可以自动生成 UpdateCommand 。然后, SqlCommandBuilder 将生成其他所有未设置的命令。此生成逻辑要求 DataSet 中存在键列信息。如果执行此命令返回行,更新的行可能会合并到 DataSet 中,具体取决于如何设置 SqlCommand 对象的 UpdatedRowSource 属性

下面的实例将创建一个 SqlDataAdapter 并设置 UpdateCommand 属性。假定已经创建一个 SqlConnection 对象

public static SqlDataAdapter CreateCustomerAdapter(SqlConnection conn){ SqlDataAdapter da = new SqlDataAdapter(); SqlCommand cmd; SqlParameter parm;// Create the UpdateCommand. cmd = new SqlCommand("UPDATE Customers SET CustomerID = @CustomerID, CompanyName = @Co

mpanyName " +"WHERE CustomerID = @oldCustomerID", conn); cmd.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID"); cmd.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40, "CompanyName"); parm = cmd.Parameters.Add("@oldCustomerID", SqlDbType.NChar, 5, "CustomerID"); parm.SourceVersion = DataRowVersion.Original; da.UpdateCommand = cmd; return da;}

Page 18: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 属性• UpdatedRowSource 属性

1. Both -将输出参数和第一个返回行都映射到 DataSet 中的已更改的行

2. FirstReturnedRecord -将第一个返回行中的数据映射到 DataSet 中的已更改的行

3. None -忽略任何返回的参数或行4. OutputParameters -将输出参数映射到 DataSet 中的已更改的行

Page 19: 数据适配器 - SqlDataAdapter 类

创建 SqlDataAdapter 实例public static void CreateSqlDataAdapter() { SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"); SqlConnection custConn = custDA.SelectCommand.Connection;

custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey; custDA.InsertCommand = new SqlCommand("INSERT INTO Customers (CustomerID, CompanyName) " + "VALUES (@CustomerID, @CompanyName)", custConn); custDA.UpdateCommand = new SqlCommand("UPDATE Customers SET CustomerID = @CustomerID, CompanyName

= @CompanyName " +"WHERE CustomerID = @oldCustomerID", custConn); custDA.DeleteCommand = new SqlCommand("DELETE FROM Customers WHERE CustomerID = @CustomerID", cust

Conn);

custDA.InsertCommand.Parameters.Add("@CustomerID", SqlDbType.Char, 5, "CustomerID"); custDA.InsertCommand.Parameters.Add("@CompanyName", SqlDbType.VarChar, 40, "CompanyName"); custDA.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.Char, 5, "CustomerID"); custDA.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.VarChar, 40, "CompanyName"); custDA.UpdateCommand.Parameters.Add("@oldCustomerID", SqlDbType.Char, 5, "CustomerID").SourceVersion = Dat

aRowVersion.Original;

custDA.DeleteCommand.Parameters.Add("@CustomerID", SqlDbType.Char, 5, "CustomerID").SourceVersion = DataRowVersion.Original;

}

Page 20: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 方法- fill

• Fill 方法-在 DataSet 中添加或刷新行以匹配数据源中的行• Fill 方法使用 SELECT 语句从数据源中检索数据。与 Select 命令关联的 IDbC

onnection 对象必须有效,但不需要将其打开。如果调用 Fill 之前 IDbConnection 已关闭,则将其打开以检索数据,然后再将其关闭。如果调用 Fill 之前连接已打开,它将保持打开状态。

• 如果在填充数据集时遇到错误,则错误发生之前添加的行将保留在数据集中。操作的剩余部分被中止。

• 如果命令不返回任何行,则不向 DataSet 中添加表,并且不引发异常。• 如果 DbDataAdapter 对象在填充 DataTable 时遇到重复列,它将以“ columnna

me1” 、“ columnname2” 、“ columnname3” 这种模式命名后面的列。如果传入数据包含未命名的列,它们将按“ Column1” 、“ Column2” 的模式放在 DataSet 中。

• 当指定的查询返回多项结果时,每个返回查询的行的结果集都放置在单独的表中。将整数值追加到指定的表名从而对其他结果集进行命名(例如“ Table” 、“ Table1” 、“ Table2” 等)。如果某个查询不返回行,则不会为该查询创建表。因此,如果先处理一个插入查询,然后再处理一个选择查询,那么由于为选择查询创建的表是第一个表,所以该表将被命名为“ Table” 。在应用程序中使用列名和表名时应小心,一定不要与这些命名模式发生冲突。

Page 21: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 方法- fill

• 当用于填充 DataSet 的 SELECT 语句(例如批处理 SQL 语句)返回多项结果时,如果其中一项结果包含错误,则将跳过所有后面的结果并且不将其添加到 DataSet 中。

• 当使用后面的 Fill 调用来刷新 DataSet 的内容时,必须满足以下两个条件: 1. 该 SQL 语句应该与最初用来填充 DataSet 的语句匹配。 2. 必须存在键列信息。 • 如果主键信息存在,则协调任何重复的行,并且这些重复行将只在与 DataSet 对应

的 DataTable 中出现一次。可以通过 FillSchema (通过指定 DataTable 的 PrimaryKey 属性),或者通过将 MissingSchemaAction 属性设置为 AddWithKey 来设置主键信息。

• 如果 SelectCommand 返回 OUTER JOIN 的结果,则 DataAdapter 不为生成的 DataTable 设置 PrimaryKey 值。必须显式定义主键,确保正确地解析重复行。注意 当处理返回多项结果的批处理 SQL 语句时,用于 OLE DB 的 .NET Framework 数据提供程序的 FillSchema 的实现只为第一项结果检索架构信息。若要为多项结果检索架构信息,请使用 MissingSchemaAction 设置为 AddWithKey 的 Fill 。

Page 22: 数据适配器 - SqlDataAdapter 类

在 DataSet 中添加或刷新行以匹配使用 DataSet 和 DataTable 名称的数据源中的行public void GetMyRecords() { // ... // create myDataSet and myDataAdapter // ... myDataAdapter.Fill(myDataSet, "Categories");}

Fill 方法支持以下情况: DataSet 包含多个 DataTable 对象,而这些对象的名称只有大小写不同。在这种情况下, Fill 执行区分大小写的比较以查找相应的表,如果不存在完全匹配的表,则新建一个。下面的 C# 代码阐释该行为。

DataSet dataset = new DataSet();dataset.Tables.Add("aaa");dataset.Tables.Add("AAA");adapter.Fill(dataset, "aaa"); // Fills "aaa", which already exists in the DataSet.adapter.Fill(dataset, "Aaa"); // Adds a new table called "Aaa".

如果调用 Fill 并且 DataSet 只包含一个其名称只有大小写不同的 DataTable ,则更新该 DataTable 。在这种情况下,比较不区分大小写。下面的 C# 代码阐释该行为。

DataSet dataset = new DataSet();dataset.Tables.Add("aaa");adapter.Fill(dataset, "AAA"); // Fills table "aaa" because only one similarly named table is in the

DataSet.

Page 23: 数据适配器 - SqlDataAdapter 类

在 DataSet 的指定范围中添加或刷新行以匹配使用 DataSet 和 DataTable 名称的数据源中的行

public int Fill(DataSet, int, int, string);

public int Fill( DataSet dataSet, int startRecord, int maxRecords, string srcTable );

参数dataSet 要用记录和架构(如果必要)填充的 DataSet 。 startRecord 从其开始的从零开始的记录号。 maxRecords 要检索的最大记录数。 srcTable 用于表映射的源表的名称。

下面的示例利用 categories 表中从第 10 行开始的 15 行数据来填充 DataSet 。public void GetMyRecords() {

// ...

// create myDataSet and myDataAdapter

// ...

myDataAdapter.Fill(myDataSet,9,15,"Categories");

}

Page 24: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 方法- Update 方法

• 为指定的 DataRow 对象数组中每个已插入、已更新或已删除的行调用相应的 INSERT 、 UPDATE 或 DELETE 语句

• 当应用程序调用 Update 方法时, DbDataAdapter根据 DataSet 中配置的索引顺序为每一行检查 RowState 属性,并迭代执行所需的 INSERT 、 UPDATE 或 DELETE 语句。例如,由于 DataTable 中行的排序, Update 可能先执行一个 DELETE 语句,接着执行一个 INSERT 语句,然后再执行另一个 DELETE 语句。

• 应注意,这些语句不是作为批处理进程执行的;每一行都是单独更新的。在必须控制语句类型顺序的情况下(例如, INSERT 在 UPDATE 之前),应用程序可以调用 GetChanges 方法。有关更多信息,请参见使用 DataAdapter 和 DataSet 更新数据库。

• 如果未指定 INSERT 、 UPDATE 或 DELETE 语句, Update 方法会生成异常。但是,如果设置 .NET Framework 数据提供程序的 SelectCommand 属性,则可以创建 SqlCommandBuilder 或 OleDbCommandBuilder 对象来为单个表更新自动生成 SQL 语句。然后, CommandBuilder 将生成其他任何未设置的 SQL 语句。此生成逻辑要求 DataSet 中存在键列信息。有关更多信息,请参见自动生成的命令。

• Update 方法在执行更新之前从第一个映射列出的表中检索行。然后, Update 使用 UpdatedRowSource 属性的值刷新该行。忽略返回的任何其他行。

• 在将任何数据加载回 DataSet 之后,将引发 OnRowUpdated事件,从而允许用户检查经协调的 DataSet 行以及该命令返回的任何输出参数。在对一行成功进行更新之后,将接受对该行的更改

Page 25: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 方法- Update 方法

• 当使用 Update 时,执行的顺序如下: 1. 将 DataRow 中的值移至参数值。 2. 引发 OnRowUpdating事件。 3. 执行命令。 4. 如果该命令设置为 FirstReturnedRecord ,返回的第一项结果将放置在

DataRow 中。 5. 如果存在输出参数,它们将被放在 DataRow 中。 6. 引发 OnRowUpdated事件。 7. 调用 AcceptChanges 。 • 与 DbDataAdapter 关联的每个命令通常都有一个与其关联的参数集合。

参数通过 .NET Framework 数据提供程序的 Parameter 类的 SourceColumn 和 SourceVersion 属性映射到当前行。 SourceColumn 引用 DataTable 列,而 DbDataAdapter 引用该列来获取当前行的参数值

Page 26: 数据适配器 - SqlDataAdapter 类

SqlDataAdapter 方法- Update 方法

• SourceColumn 属性还用于将输出或输入 /输出参数的值映射回 DataSet 。如果它引用一个不存在的列,则会生成异常。

• .NET Framework 数据提供程序的 Parameter 类的 SourceVersion 属性确定使用列值的哪个版本: Original 、 Current 还是 Proposed 。该功能通常用于在 UPDATE 语句的 WHERE 子句中包含初始值,以检查开放式并发冲突。

注意 如果在更新行时出错,则会引发异常并停止执行更新。若要在遇到错误时继续更新操作而不生成异常,请在调用 Update 之前将 ContinueUpdateOnError 属性设置为 true 。您还可以在 SqlDataAdapter 或 OleDbDataAdapter 的 RowUpdated 事件中逐行对错误作出响应。若要在 RowUpdated 事件中继续更新操作而不生成异常,请将 RowUpdatedEventArgs 的 Status 属性设置为 Continue 。

Page 27: 数据适配器 - SqlDataAdapter 类

Update 方法程序实例为指定的 DataRow 对象数组中每个已插入、已更新或已删除的行调用相应的 INSERT 、 UPDATE

或 DELETE 语句

public DataSet CreateCmdsAndUpdate(DataSet myDataSet,string myConnection,string mySelectQuery,string myTableName)

{ OleDbConnection myConn = new OleDbConnection(myConnection); OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(); myDataAdapter.SelectCommand = new OleDbCommand(mySelectQuery, myConn); OleDbCommandBuilder custCB = new OleDbCommandBuilder(myDataAdapter);

myConn.Open(); DataSet custDS = new DataSet(); myDataAdapter.Fill(custDS);

//code to modify data in dataset here //Insert new records from DataSet DataRow[] myDataRowArray = custDS.Tables[0].Select(null, null, DataViewRowState.Added); myDataAdapter.Update(myDataRowArray); myConn.Close(); return custDS; }

Page 28: 数据适配器 - SqlDataAdapter 类

Update 方法程序实例为指定的 DataRow 对象数组中每个已插入、已更新或已删除的行调用相应的 INSERT 、 UPDATE

或 DELETE 语句

public DataSet CreateCmdsAndUpdate(DataSet myDataSet,string myConnection,string mySelectQuery,string myTableName)

{ OleDbConnection myConn = new OleDbConnection(myConnection); OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(); myDataAdapter.SelectCommand = new OleDbCommand(mySelectQuery, myConn); OleDbCommandBuilder custCB = new OleDbCommandBuilder(myDataAdapter);

myConn.Open(); DataSet custDS = new DataSet(); myDataAdapter.Fill(custDS);

//code to modify data in dataset here //Insert new records from DataSet DataRow[] myDataRowArray = custDS.Tables[0].Select(null, null, DataViewRowState.Added); myDataAdapter.Update(myDataRowArray); myConn.Close(); return custDS; }

Page 29: 数据适配器 - SqlDataAdapter 类

public DataSet CreateCmdsAndUpdate(DataSet myDataSet,string myConnection,string mySelectQuery,string myTableName)

{

OleDbConnection myConn = new OleDbConnection(myConnection);

OleDbDataAdapter myDataAdapter = new OleDbDataAdapter();

myDataAdapter.SelectCommand = new OleDbCommand(mySelectQuery, myConn);

OleDbCommandBuilder custCB = new OleDbCommandBuilder(myDataAdapter);

myConn.Open();

DataSet custDS = new DataSet();

myDataAdapter.Fill(custDS);

//code to modify data in dataset here

myDataAdapter.Update(custDS);

myConn.Close();

return custDS;

}

为指定 DataSet 中每个已插入、已更新或已删除的行调用相应的 INSERT 、 UPDATE 或 DELETE 语句

Page 30: 数据适配器 - SqlDataAdapter 类

为指定 DataTable 中每个已插入、已更新或已删除的行调用相应的 INSERT 、 UPDATE 或 DELETE 语句

public DataTable CreateCmdsAndUpdate(DataSet myDataSet,string myConnection,string mySelectQuery,string myTableName)

{

OleDbConnection myConn = new OleDbConnection(myConnection);

OleDbDataAdapter myDataAdapter = new OleDbDataAdapter();

myDataAdapter.SelectCommand = new OleDbCommand(mySelectQuery, myConn);

OleDbCommandBuilder custCB = new OleDbCommandBuilder(myDataAdapter);

myConn.Open();

DataTable custDT = new DataTable();

myDataAdapter.Fill(custDT);

//code to modify data in DataTable here

myDataAdapter.Update(custDT);

myConn.Close();

return custDT;

}

Page 31: 数据适配器 - SqlDataAdapter 类

为具有指定 DataTable 名称的 DataSet 中每个已插入、已更新或已删除的行调用相应的 INSERT 、 UPDATE 或 DELETE 语句public DataSet CreateCmdsAndUpdate(DataSet myDataSet,string myConnection,string mySelectQuery,string

myTableName)

{

OleDbConnection myConn = new OleDbConnection(myConnection);

OleDbDataAdapter myDataAdapter = new OleDbDataAdapter();

myDataAdapter.SelectCommand = new OleDbCommand(mySelectQuery, myConn);

OleDbCommandBuilder custCB = new OleDbCommandBuilder(myDataAdapter);

myConn.Open();

DataSet custDS = new DataSet();

myDataAdapter.Fill(custDS);

//code to modify data in dataset here

myDataAdapter.Update(custDS, myTableName);

myConn.Close();

return custDS;

}

Page 32: 数据适配器 - SqlDataAdapter 类

DataAdapter 事件• ADO.NET DataAdapter 公开了三个可用于响应对数据源中的

数据所作更改的事件。下表显示了这些 DataAdapter 事件。

事件 说明RowUpdating 将要开始对某行执行 UPDATE 、 INSERT 或

DELETE 操作(通过调用 Update 方法之一)

RowUpdated 对某行的 UPDATE 、 INSERT 或 DELETE 操作(通过调用 Update 方法之一)已完成。

FillError 在 Fill 操作过程中出错。

Page 33: 数据适配器 - SqlDataAdapter 类

RowUpdating 和 RowUpdated• 在数据源中处理对 DataSet 中某行的任何更新之前,将引发 RowUpdating 。在数据源中处理对

DataSet 中某行的任何更新之后,将引发 RowUpdated 。因此,可以使用 RowUpdating 在更新行为发生之前对其进行修改,在更新将发生时提供附加的处理,保留对已更新行的引用,取消当前更新操作并将其安排在以后进行批处理,等等。 RowUpdated 用于响应在更新过程中发生的错误和异常。可以向 DataSet 以及重试逻辑等添加错误信息。

• 向 RowUpdating 和 RowUpdated 事件传递的 RowUpdatingEventArgs 和 RowUpdatedEventArgs 参数包括: Command 属性,它引用用来执行更新的 Command 对象; Row 属性,它引用包含更新信息的 DataRow 对象; StatementType 属性,它指示所执行的更新类型; TableMapping(如果适用);以及操作的 Status 。

• SqlDataAdapter 的 OnRowUpdating事件处理程序接收一个 SqlRowUpdatingEventArgs 类型的参数,它包含与此事件相关的数据。下列 SqlRowUpdatingEventArgs 属性提供特定于此事件的信息。

属性 说明Command 获取或设置进行 Update 时执行的 SqlCommand 。Errors (从 RowUpdatingEventArgs 继承) 获取当 Command 执行时 .NET Framework 数据提供程序 生成的任何错误。Row (从 RowUpdatingEventArgs 继承)获取要通过 Update发送的 DataRow 。StatementType (从 RowUpdatingEventArgs 继承)

获取要执行的 SQL 语句的类型。Status (从 RowUpdatingEventArgs 继承)

获取 Command 属性的 UpdateStatus 。TableMapping (从 RowUpdatingEventArgs 继承)

获取要通过 Update 发送的 DataTableMapping 。

Page 34: 数据适配器 - SqlDataAdapter 类

RowUpdating 和 RowUpdated

• 可以使用 Status 属性来确定该操作过程中是否出错,如果需要,还可以控制对当前和结果行执行的操作。当该事件发生时, Status 属性将等于 Continue 或 ErrorsOccurred 。

• 下表显示为了控制更新过程中的后继操作,可以将 Status 属性设置为的值。Continue 继续执行更新操作。ErrorsOccurred 中止更新操作并引发异常。SkipCurrentRow 忽略当前行并继续执行更新操作。SkipAllRemainingRows 中止更新操作但不引发异常。

• 如果将 Status 属性设置为 ErrorsOccurred ,则将引发异常。您可以通过将 Errors 属性设置为预期异常来控制所引发的异常。如果使用其他 Status 值之一,则将防止引发异常。

• 也可以使用 ContinueUpdateOnError 属性为已更新的行处理错误。如果 DataAdapter.ContinueUpdateOnError 为 true ,那么当对行结果的更新导致异常时,该异常的文本将被放入特定行的 RowError 信息中,并且处理将会继续而不会引发异常。这样,当 Update 完成时,就可以对错误作出响应,而不是对 RowUpdated 事件作出响应,这使得能够在遇到错误时响应错误。

Page 35: 数据适配器 - SqlDataAdapter 类

RowUpdating 和 RowUpdated

• 当使用 Update 时,每一个更新的数据行都会发生两个事件。执行顺序如下:

1. 将 DataRow 中的值移至参数值。 2. 引发 OnRowUpdating事件。 3. 执行命令。 4. 如果该命令设置为 FirstReturnedRecord ,则第一个返回结

果放在 DataRow 中。 5. 如果存在输出参数,它们将被放在 DataRow 中。 6. 引发 OnRowUpdated事件。 7. 调用 AcceptChanges 。

Page 36: 数据适配器 - SqlDataAdapter 类

例 1 :以下代码示例显示如何添加和移除事件处理程序。 RowUpdating 事件处理程序编写所有已删除记录的日志,该日志带有一个时间戳。 RowUpdated 事件处理程序将错误信息添加到 DataSet 中行的 RowError 属性,取消异常,并继续处理(静像 ContinueUpdateOnError = true 的行为)。

SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", nwindConn);// Add handlers.custDA.RowUpdating += new SqlRowUpdatingEventHandler(OnRowUpdating);custDA.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);// Set DataAdapter command properties, fill the DataSet, and modify the DataSet.custDA.Update(custDS, "Customers");// Remove handlers.custDA.RowUpdating -= new SqlRowUpdatingEventHandler(OnRowUpdating);custDA.RowUpdated -= new SqlRowUpdatedEventHandler(OnRowUpdated);protected static void OnRowUpdating(object sender, SqlRowUpdatingEventArgs args){ if (args.StatementType == StatementType.Delete) { System.IO.TextWriter tw = System.IO.File.AppendText("Deletes.log"); tw.WriteLine("{0}: Customer {1} Deleted.", DateTime.Now, args.Row["CustomerID", DataRowVersion.Original]); tw.Close(); }}protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args){ if (args.Status == UpdateStatus.ErrorsOccurred) { args.Row.RowError = args.Errors.Message; args.Status = UpdateStatus.SkipCurrentRow; }}

Page 37: 数据适配器 - SqlDataAdapter 类

例 2// handler for RowUpdating event protected static void OnRowUpdating(object sender, SqlRowUpdatingEventArgs e) { PrintEventArgs(e); } // handler for RowUpdated event protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs e) { PrintEventArgs(e); } public static int Main(String[] args) { const string CONNECTION_STRING = "Persist Security Info=False;Integrated Security=SSPI;database=n

orthwind;server=(local)"; const string SELECT_ALL = "select * from Products"; // create DataAdapter SqlDataAdapter rAdapter = new SqlDataAdapter(SELECT_ALL, CONNECTION_STRING); SqlCommandBuilder cb = new SqlCommandBuilder(rAdapter); // Create and fill dataset (select only first 5 rows) DataSet rDataSet = new DataSet(); rAdapter.Fill(rDataSet, 0, 5, "Table"); // Modify dataSet DataTable rTable = rDataSet.Tables["Table"]; rTable.Rows[0][1] = "new product";

Page 38: 数据适配器 - SqlDataAdapter 类

// add handlers rAdapter.RowUpdating += new SqlRowUpdatingEventHandler( OnRowUpdating ); rAdapter.RowUpdated += new SqlRowUpdatedEventHandler( OnRowUpdated ); // update, this operation fires two events (RowUpdating/RowUpdated) per changed row rAdapter.Update(rDataSet, "Table"); // remove handlers rAdapter.RowUpdating -= new SqlRowUpdatingEventHandler( OnRowUpdating ); rAdapter.RowUpdated -= new SqlRowUpdatedEventHandler( OnRowUpdated ); return 0; } protected static void OnRowUpdating(object sender, SqlRowUpdatingEventArgs args) { Console.WriteLine("OnRowUpdating"); Console.WriteLine(" event args: ("+ " command=" + args.Command + " commandType=" + args.StatementType + " status=" + args.Status + ")"); } protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args) { Console.WriteLine("OnRowUpdated"); Console.WriteLine( " event args: ("+ " command=" + args.Command + " commandType=" + args.StatementType + " recordsAffected=" + args.RecordsAffected + " status=" + args.Status + ")" ); }

Page 39: 数据适配器 - SqlDataAdapter 类

FillError• 当 Fill 操作过程中出错时, DataAdapter 将发出 FillError 事件。当所添

加行中的数据必须损失一些精度才能转换成 .NET Framework 类型时,通常会发生这种类型的错误。

• 如果在 Fill 操作过程中出错,则当前行将不会被添加到 DataTable 中。FillError 事件使您能够解决错误并添加当前行,或者忽略已排除的行并继续执行 Fill 操作。

• 向 FillError 事件传递的 FillErrorEventArgs 可以包含几项可用于响应和解决错误的属性。下表显示了 FillErrorEventArgs 对象的属性。属性 说明Errors 已发生的 Exception 。DataTable 出错时所填充的 DataTable 对象。Values 一个对象数组,它包含出错时所添加的行的值。 Values 数组的序号引用对应于所添加的行的列的序号引用。例如, Values[0] 是作为当前行的第一列添加的值。Continue 用于选择是否引发 Exception 。如果将 Continue 属性设置为 false ,则将中止当前 Fill 操作并引发异常。如果将 Continue 设置为 true ,那么即使出错,仍将继续执行 Fill 操作。

Page 40: 数据适配器 - SqlDataAdapter 类

• 以下代码示例为 DataAdapter 的 FillError 事件添加一个事件处理程序。在 FillError 事件代码中,该示例确定是否可能出现精度损失,并提供响应该异常的机会

myDA.FillError += new FillErrorEventHandler(FillError);

DataSet myDS = new DataSet();myDA.Fill(myDS, "MyTable");

protected static void FillError(object sender, FillErrorEventArgs args){ if (args.Errors.GetType() == typeof(System.OverflowException)) { // Code to handle precision loss. //Add a row to table using the values from the first two columns. DataRow myRow = args.DataTable.Rows.Add(new object[] {args.Values[0], args.Values[1],

DBNull.Value}); //Set the RowError containing the value for the third column. args.RowError = "OverflowException Encountered. Value from data source: " + args.Values

[2];

args.Continue = true; }}