有三个操作可改变表的状态:
• | 插入一个新行 |
• | 删除一个现有的行 |
• | 更新一个现有的行 |
对于其中的每一个关键操作,数据适配器都会定义一个作为属性公开的自定义的命令对象。这样的属性包括 InsertCommand、DeleteCommand 和 UpdateCommand。程序员负责为这些属性分配有意义的命令对象,例如,SqlCommand 对象。
仅提供的 InsertCommand、DeleteCommand 和 UpdateCommand 属性就代表了从 ADO 到 ADO.NET 的巨大突破。利用这种属性,您可以对内存中的更新提交到数据库服务器的方式进行前所未有的控制。如果您不满意 ADO.NET 生成的更新代码,现在则可以修改这些更新代码,而不会否定批处理更新的整体特性。使用 ADO 的时候,您对库静默生成的 SQL 命令毫无控制权。而在 ADO.NET 中,利用公开显示的命令对象,您可以使用更符合用户期望的自定义存储过程或 SQL 语句来应用更新。特别是,您可以对交叉引用的表使用批处理更新系统,甚至可以诸如 Active Directory™ 或 Indexing Services 这样的非 SQL 数据提供程序为目标。
更新命令应该针对表中每个更改的行运行,并且必须非常通用,以适应不同的值。对于这种任务,非常适合使用命令参数,只要您可以将它们绑定到数据库列的值。ADO.NET 参数对象公开两个用于这种绑定的属性,例如, SourceColumn 和 SourceVersion。尤其是 SourceColumn,它表示一种指示参数值的间接方式。您可以使用列名设置 SourceColumn 属性,并且使批处理更新机制不时地提取有效值,而不是使用 Value 属性并用标量值设置它。
SourceVersion 指示应该读取列上的哪个值。默认情况下,ADO.NET 会返回行的当前值。另一种方法是,您可以选择原始值和 DataRowVersion 枚举中的所有值。
如果您希望对 Northwind 的 Employees 表中的几个列进行批处理更新,可以使用以下自定义命令。INSERT 命令的定义如下:
StringBuilder sb = new StringBuilder(""); sb.Append("INSERT Employees (firstname, lastname) VALUES("); sb.Append("@sFirstName, @sLastName)"); da.InsertCommand = new SqlCommand(); da.InsertCommand.CommandText = sb.ToString(); da.InsertCommand.Connection = conn;
所有参数都将添加到数据适配器的 Parameters 集合并绑定到一个数据表列。
SqlParameter p1 = new SqlParameter("@sFirstName", SqlDbType.NVarChar, 10); p1.SourceVersion = DataRowVersion.Current; p1.SourceColumn = "firstname"; da.InsertCommand.Parameters.Add(p1); SqlParameter p2 = new SqlParameter("@sLastName", SqlDbType.NVarChar, 30); p2.SourceVersion = DataRowVersion.Current; p2.SourceColumn = "lastname"; da.InsertCommand.Parameters.Add(p2);
注意,自动递增的列不应该列在 INSERT 命令的语法中,因为它们的值是由数据源生成的。
UPDATE 命令需要确定一个特定的行来应用其更改。为此,您可以使用 WHERE 子句,在该子句中对参数化的值与键字段进行比较。在这种情况下,WHERE 子句中使用的参数必须绑定到行的原始值,而不是当前值。
StringBuilder sb = new StringBuilder(""); sb.Append("UPDATE Employees SET "); sb.Append("lastname=@sLastName, firstname=@sFirstName "); sb.Append("WHERE employeeid=@nEmpID"); da.UpdateCommand = new SqlCommand(); da.UpdateCommand.CommandText = sb.ToString(); da.UpdateCommand.Connection = conn; // p1 and p2 set as before : p3 = new SqlParameter("@nEmpID", SqlDbType.Int); p3.SourceVersion = DataRowVersion.Original; p3.SourceColumn = "employeeid"; da.UpdateCommand.Parameters.Add(p3);
最后,DELETE 命令需要用 WHERE 子句来确定要删除的行。在这种情况下,您需要使用行的原始版本来绑定参数值。
StringBuilder sb = new StringBuilder(""); sb.Append("DELETE FROM Employees "); sb.Append("WHERE employeeid=@nEmpID"); da.DeleteCommand = new SqlCommand(); da.DeleteCommand.CommandText = sb.ToString(); da.DeleteCommand.Connection = conn; p1 = new SqlParameter("@nEmpID", SqlDbType.Int); p1.SourceVersion = DataRowVersion.Original; p1.SourceColumn = "employeeid"; da.DeleteCommand.Parameters.Add(p1);
SQL 命令的实际结构取决于您。这些命令不一定是普通的 SQL 语句,它们可以是更有效的存储过程(如果您想采用这种方向)。如果存在某个很具体的风险 - 其他人可能更新您读取和修改的行,那么您可能想采取一些更有效的防范措施。如果是这种情况,您可以在 DELETE 和 UPDATE 命令中使用一个限制性更强的 WHERE 子句。WHERE 子句可以明确地确定行,但同时还应确保所有列仍然保留原始值。
UPDATE Employees SET field1=@new_field1, field2=@new_field2, ???…, fieldn=@new_fieldn WHERE field1=@old_field1 AND field2=@old_field2 AND : fieldn=@old_fieldn
注意,您无需填充所有命令参数,只填充您计划使用的那些即可。如果代码要使用尚未指定的命令,则会引发异常。为批处理更新过程设置命令可能需要许多代码,但您无需在每一次进行批处理更新时都编写大量代码。实际上,在相当多的情况下,ADO.NET 都能为您自动生成有效的更新命令。