1 / 40

数据适配器 - SqlDataAdapter 类

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

nicole
Download Presentation

数据适配器 - SqlDataAdapter 类

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 数据适配器-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);

  2. 数据适配器- SqlDataAdapter类 • 当 SqlDataAdapter填充 DataSet时,它将为返回的数据创建必要的表和列(如果它们尚不存在)。但是,除非 MissingSchemaAction属性设置为 AddWithKey,否则这个隐式创建的架构中就将不包括主键信息。也可以在使用 FillSchema 为数据集填充数据前,让 SqlDataAdapter创建 DataSet的架构(包括主键信息)。 • SqlDataAdapter与 SqlConnection和 SqlCommand一起使用,以便在连接到 Microsoft SQL Server 数据库时提高性能。 • SqlDataAdapter还包括 SelectCommand、InsertCommand、DeleteCommand、UpdateCommand 和 TableMappings 属性,使数据的加载和更新更加方便。 • 当创建 SqlDataAdapter的实例时,读/写属性将被设置为初始值。有关这些值的列表,参见 SqlDataAdapter构造函数。

  3. SqlDataAdapter构造函数 • public SqlDataAdapter(); 例: SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"); SqlDataAdapter custDA = new SqlDataAdapter(); custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

  4. 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;

  5. SqlDataAdapter构造函数 • public SqlDataAdapter(string, SqlConnection):使用 SelectCommand和 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;

  6. SqlDataAdapter构造函数 • public SqlDataAdapter(string, string):用 SelectCommand和一个连接字符串初始化 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;

  7. SqlDataAdapter属性 • 当创建 SqlDataAdapter的实例时,下面的读/写属性将设置为以下初始值 Properties MissingMappingAction-确定传入数据没有匹配的表或列时需要执行的操作 值: Passthrough-创建源列或源表,并使用其原始名称将其添加到 DataSet(初始值) Error-如果缺少指定的列映射,则生成 InvalidOperationException Ignore-忽略没有映射的列或表。返回空引用(Visual Basic 中为 Nothing)。 MissingSchemaAction-确定现有 DataSet架构与传入数据不匹配时需要执行的操作 值: MissingSchemaAction.Add-添加必需的列以完成架构(初始值) AddWithKey-添加必需的列和主键信息以完成架构 Error-如果缺少指定的列映射,则生成 InvalidOperationException Ignore-忽略额外列 可以通过单独调用属性来更改任何这些属性的值

  8. SqlDataAdapter属性 • AcceptChangesDuringFill(从 DataAdapter继承)获取或设置一个值,该值指示在任何 Fill操作过程中,在将 AcceptChanges添加到 DataTable之后是否针对 DataRow调用它,如果在 DataRow上调用 AcceptChanges,则为 true;否则为 false。默认值为 true • Container(从 Component继承)获取 IContainer,它包含 Component。如果 Component未在 IContainer中封装,则该值为空引用。IContainer提供容器的功能。容器是在逻辑上包含零个或更多个组件的对象。容器是封装和跟踪零个或更多个组件的对象。在此上下文中,包容是指逻辑包容,而不是直观包容。可以在多种方案下使用组件和容器,包括可视化方案和非可视化方案。对实施者的说明: 要成为容器,类必须实现 IContainer接口,该接口支持添加、移除和检索组件的方法

  9. SqlDataAdapter属性 • TableMappings(从 DataAdapter继承)获取一个集合,它提供源表和 DataTable之间的主映射,默认值是一个空集合。当协调更改时,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); }

  10. 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。

  11. DataTable 和 DataColumn 映射 • 以下代码示例创建一个 DataTableMapping(从 System.Data.Common 命名空间)并通过将其命名为“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 对象。

  12. 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中的表映射名称发生冲突。如果提供的名称已经存在,将引发异常。

  13. 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")

  14. 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; }

  15. 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; }

  16. 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; }

  17. 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 = @CompanyName " +"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; }

  18. SqlDataAdapter属性 • UpdatedRowSource 属性 • Both-将输出参数和第一个返回行都映射到 DataSet 中的已更改的行 • FirstReturnedRecord-将第一个返回行中的数据映射到 DataSet中的已更改的行 • None-忽略任何返回的参数或行 • OutputParameters-将输出参数映射到 DataSet 中的已更改的行

  19. 创建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", custConn); 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 = DataRowVersion.Original; custDA.DeleteCommand.Parameters.Add("@CustomerID", SqlDbType.Char, 5, "CustomerID").SourceVersion = DataRowVersion.Original; }

  20. SqlDataAdapter方法-fill • Fill 方法-在 DataSet中添加或刷新行以匹配数据源中的行 • Fill 方法使用 SELECT 语句从数据源中检索数据。与 Select 命令关联的 IDbConnection对象必须有效,但不需要将其打开。如果调用 Fill 之前 IDbConnection 已关闭,则将其打开以检索数据,然后再将其关闭。如果调用 Fill 之前连接已打开,它将保持打开状态。 • 如果在填充数据集时遇到错误,则错误发生之前添加的行将保留在数据集中。操作的剩余部分被中止。 • 如果命令不返回任何行,则不向 DataSet中添加表,并且不引发异常。 • 如果 DbDataAdapter对象在填充 DataTable时遇到重复列,它将以“columnname1”、“columnname2”、“columnname3”这种模式命名后面的列。如果传入数据包含未命名的列,它们将按“Column1”、“Column2”的模式放在 DataSet 中。 • 当指定的查询返回多项结果时,每个返回查询的行的结果集都放置在单独的表中。将整数值追加到指定的表名从而对其他结果集进行命名(例如“Table”、“Table1”、“Table2”等)。如果某个查询不返回行,则不会为该查询创建表。因此,如果先处理一个插入查询,然后再处理一个选择查询,那么由于为选择查询创建的表是第一个表,所以该表将被命名为“Table”。在应用程序中使用列名和表名时应小心,一定不要与这些命名模式发生冲突。

  21. SqlDataAdapter方法-fill • 当用于填充 DataSet 的 SELECT 语句(例如批处理 SQL 语句)返回多项结果时,如果其中一项结果包含错误,则将跳过所有后面的结果并且不将其添加到 DataSet 中。 • 当使用后面的 Fill 调用来刷新 DataSet 的内容时,必须满足以下两个条件: • 该 SQL 语句应该与最初用来填充 DataSet的语句匹配。 • 必须存在键列信息。 • 如果主键信息存在,则协调任何重复的行,并且这些重复行将只在与 DataSet 对应的 DataTable 中出现一次。可以通过 FillSchema(通过指定 DataTable 的 PrimaryKey属性),或者通过将 MissingSchemaAction 属性设置为 AddWithKey 来设置主键信息。 • 如果 SelectCommand 返回 OUTER JOIN 的结果,则 DataAdapter 不为生成的 DataTable 设置 PrimaryKey 值。必须显式定义主键,确保正确地解析重复行。 注意   当处理返回多项结果的批处理 SQL 语句时,用于 OLE DB 的 .NET Framework 数据提供程序的 FillSchema 的实现只为第一项结果检索架构信息。若要为多项结果检索架构信息,请使用 MissingSchemaAction 设置为 AddWithKey 的 Fill。

  22. 在 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.

  23. 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"); }

  24. 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行以及该命令返回的任何输出参数。在对一行成功进行更新之后,将接受对该行的更改

  25. SqlDataAdapter方法-Update 方法 • 当使用 Update时,执行的顺序如下: • 将 DataRow 中的值移至参数值。 • 引发 OnRowUpdating事件。 • 执行命令。 • 如果该命令设置为 FirstReturnedRecord,返回的第一项结果将放置在 DataRow中。 • 如果存在输出参数,它们将被放在 DataRow 中。 • 引发 OnRowUpdated事件。 • 调用 AcceptChanges。 • 与 DbDataAdapter关联的每个命令通常都有一个与其关联的参数集合。参数通过 .NET Framework 数据提供程序的 Parameter类的 SourceColumn和 SourceVersion属性映射到当前行。SourceColumn引用 DataTable列,而 DbDataAdapter引用该列来获取当前行的参数值

  26. SqlDataAdapter方法-Update 方法 • SourceColumn属性还用于将输出或输入/输出参数的值映射回 DataSet。如果它引用一个不存在的列,则会生成异常。 • .NET Framework 数据提供程序的 Parameter类的 SourceVersion属性确定使用列值的哪个版本:Original、Current还是 Proposed。该功能通常用于在 UPDATE 语句的 WHERE 子句中包含初始值,以检查开放式并发冲突。 注意   如果在更新行时出错,则会引发异常并停止执行更新。若要在遇到错误时继续更新操作而不生成异常,请在调用 Update之前将 ContinueUpdateOnError 属性设置为 true。您还可以在 SqlDataAdapter 或 OleDbDataAdapter的 RowUpdated事件中逐行对错误作出响应。若要在 RowUpdated事件中继续更新操作而不生成异常,请将 RowUpdatedEventArgs的 Status属性设置为 Continue。

  27. 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; }

  28. 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; }

  29. 为指定 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); myConn.Close(); return custDS; }

  30. 为指定 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; }

  31. 为具有指定 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; }

  32. DataAdapter 事件 • ADO.NET DataAdapter 公开了三个可用于响应对数据源中的数据所作更改的事件。下表显示了这些 DataAdapter 事件。 事件 说明 RowUpdating 将要开始对某行执行 UPDATE、INSERT 或 DELETE 操作(通过调用 Update 方法之 一) RowUpdated 对某行的 UPDATE、INSERT 或 DELETE 操作(通过调用 Update 方法之一)已完成。 FillError 在 Fill 操作过程中出错。

  33. 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。

  34. RowUpdating 和 RowUpdated • 可以使用 Status属性来确定该操作过程中是否出错,如果需要,还可以控制对当前和结果行执行的操作。当该事件发生时,Status属性将等于 Continue或 ErrorsOccurred。 • 下表显示为了控制更新过程中的后继操作,可以将 Status属性设置为的值。 Continue 继续执行更新操作。 ErrorsOccurred 中止更新操作并引发异常。 SkipCurrentRow 忽略当前行并继续执行更新操作。 SkipAllRemainingRows 中止更新操作但不引发异常。 • 如果将 Status属性设置为 ErrorsOccurred,则将引发异常。您可以通过将 Errors属性设置为预期异常来控制所引发的异常。如果使用其他 Status值之一,则将防止引发异常。 • 也可以使用 ContinueUpdateOnError属性为已更新的行处理错误。如果 DataAdapter.ContinueUpdateOnError为 true,那么当对行结果的更新导致异常时,该异常的文本将被放入特定行的 RowError信息中,并且处理将会继续而不会引发异常。这样,当 Update完成时,就可以对错误作出响应,而不是对 RowUpdated事件作出响应,这使得能够在遇到错误时响应错误。

  35. RowUpdating 和 RowUpdated • 当使用 Update时,每一个更新的数据行都会发生两个事件。执行顺序如下: • 将 DataRow中的值移至参数值。 • 引发 OnRowUpdating事件。 • 执行命令。 • 如果该命令设置为 FirstReturnedRecord,则第一个返回结果放在 DataRow中。 • 如果存在输出参数,它们将被放在 DataRow中。 • 引发 OnRowUpdated事件。 • 调用 AcceptChanges。

  36. 例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; } }

  37. 例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=northwind;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";

  38. // 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 + ")" ); }

  39. 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 操作。

  40. 以下代码示例为 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; } }

More Related