使用 DataSet 来修改数据
- 为 DataTable 和 DataColumn 添加 约束
- 在 Table 中查找数据
- 在 Table 中 filter,排序
- 在 Table 中修改数据
- 如何处理 Update Failure
- 如何在 DataSet 中使用 Transaction
- 为 DataTable 和 DataColumn 添加 约束
- DataTable 的相关约束
- Unique
- 主键
- 外键
- DataColumn 的相关约束
- 是否可以接受 null 值
- 是否自增加 ID
- 文本最大长度
- 是否只读
- Unique
- 添加约束,会影响速度。所以,在调用 Fill()函数前,应该把 EnforceConstraints 属性设成 false,调用后再设成 true。
- 所有约束是保存在一个 ConstraintCollection 对象中
- 这个对象对应着 DataTable 的 Constraints 属性,
- 要添加一个 约束 到 Collection 中,可以调用它的 Add() 函数。
- 添加主键
- 对 DataSet 的影响:如果一个 DataTable是有主键的,那么即使调用 Fill()函数多次(假设每次都获取这个 table 的数据),在 dataSet 中会每次调用后自动删除重复的行;否则,重复的行不会被删除。
- 使用 DataTable 的 属性来添加主键
- 代码实例
- DataColumn[] productsPrimaryKey = new DataColumn[]
{
productsDataTable.Columns["ProductID"]
};
productsDataTable.PrimaryKey = productsPrimaryKey;
- DataColumn[] productsPrimaryKey = new DataColumn[]
- 代码解释
- 先创建一个 DataColumn[] 数组来保存该 table 的 主键(可能有多列),然后把 table 的 PrimaryKey 属性设置成这个数组。
- 在设置 PrimaryKey 后,这个对应的 DataColumn 的 AllowDBNull 和 Unique 会自动被设成 false 和 true。
- 代码实例
- 使用 ConstraintCollection 的 Add()函数来添加主键
- 这个方法没有上面一个好,因为要逐个 主键 来添加,比较麻烦。
- 代码实例
- myDataSet.Tables["Orders"].Constraints.Add
(
"Primary key constraint",
myDataSet.Tables["Orders"].Columns["OrderID"],
true
);
// 添加 Unique 约束的代码
UniqueConstraint myUC = new UniqueConstraint(myDataTable.Columns["myColumn"]);
myDataTable.Constraints.Add(myUC);
- myDataSet.Tables["Orders"].Constraints.Add
- 添加外键
- 代码实例
- ForeignKeyConstraint myFKC = new ForeignKeyConstraint(
myDataSet.Tables["Orders"].Columns["OrderID"], // 外键中的 主导方
myDataSet.Tables["Order Details"].Columns["OrderID"] // 外键中的 从属方
);
myDataSet.Tables["Order Details"].Constraints.Add(myFKC);
- ForeignKeyConstraint myFKC = new ForeignKeyConstraint(
- 注意: 是 外键中的 从属方 的值 受到 主导方 的约束。
- 代码实例
- 为 DataColumn 添加约束
- 代码实例
- DataColumn productIDDataColumn = myDataSet.Tables["Products"].Columns["ProductID"];
productIDDataColumn.AllowDBNull = false;
productIDDataColumn.AutoIncrement = true;
productIDDataColumn.AutoIncrementSeed = -1;
productIDDataColumn.AutoIncrementStep = -1;
productIDDataColumn.ReadOnly = true;
productIDDataColumn.Unique = true;
myDataSet.Tables["Products"].Columns["ProductName"].MaxLength = 40;
- DataColumn productIDDataColumn = myDataSet.Tables["Products"].Columns["ProductID"];
- 代码实例
- DataTable 的相关约束
- 在 Table 中查找数据
- 要查找某个特定主键的 dataRow,必须保证该 Table 是设置了 主键的。然后可以用以下代码进行查找:
DataRow productDataRow = productsDataTable.Rows.Find("3");
如果主键是由 多个 列组成,则可以通过以下代码查找:
object[] orderDetails = new object[] { 10248, 11 };
DataRow orderDetailDataRow = orderDetailsDataTable.Rows.Find(orderDetails);
- 要查找某个特定主键的 dataRow,必须保证该 Table 是设置了 主键的。然后可以用以下代码进行查找:
- 在 Table 中 filter,排序
- 通过 DataTable 的各个重载的 Select()函数
DataRow[] Select()
DataRow[] Select(string filterExpression)
DataRow[] Select(string filterExpression, string sortExpression)
DataRow[] Select(string filterExpression, string sortExpression, DataViewRowState myDataViewRowState) - 代码实例
- DataRow[] productDataRows = productsDataTable.Select("ProductID <= 5", "ProductID DESC", DataViewRowState.OriginalRows);
- 关于 Expression 如何规定,参见 DataColumn.Expression (可以创建非常复杂的表达式)。
- 通过 DataTable 的各个重载的 Select()函数
- 在 Table 中修改数据
- 如何更新(Update)数据
- 两种更新模式(不覆盖其他用户 & 覆盖)及其 使用
- 模式一:不覆盖其他用户所做的修改
- 模式规定:对某一行做更新时,如果发现它已经被其他用户修改过,则放弃自己所做的修改。
- 模式使用要求(以下要求同样适用于 DELETE 语句):
- 在 Update 语句中,必须包括 所有 在 SELECT 语句中的 列。
- 在修改数据之前,把值 设置成原来的值。
- 代码实例
- myUpdateCommand.CommandText = "UPDATE Customers " +
"SET CompanyName = @NewCompanyName,
WHERE CompanyName = @OldCompanyName";
myUpdateCommand.Parameters.Add("@NewCompanyName", SqlDbType.NVarChar, 40,
"CompanyName");
myUpdateCommand.Parameters.Add("@OldCompanyName", SqlDbType.NVarChar, 40, "CompanyName");
myUpdateCommand.Parameters["@OldCompanyName"].SourceVersion = DataRowVersion.Original;
- 在 Update 语句中,“Where”子句必须包括所有 在 SELECT 语句中的列,这满足模式第一个要求;要满足第二个要求,必须把 SourceVersion 设置成 DataRowVersion.Original
- myUpdateCommand.CommandText = "UPDATE Customers " +
- 模式二:最后的修改才被写入数据库
- 模式规定:对某一行做更新时,不管别人有没有修改,直接覆盖旧值。
- 模式使用要求(以下要求同样适用于 DELETE 语句):
- 在 WHERE 子句中( Update 或者 DELETE)中,只需要包括主键。
- 模式一:不覆盖其他用户所做的修改
- 两种更新模式(不覆盖其他用户 & 覆盖)及其 使用
- 如何添加 新行
- 代码实例
- DataRow myNewDataRow = myDataTable.NewRow();
myNewDataRow["CustomerID"] = "J5COM";
myNewDataRow["CompanyName"] = "J5 Company";
myNewDataRow["Address"] = "1 Main Street";myDataTable.Rows.Add(myNewDataRow);
int numOfRows = mySqlDataAdapter.Update(myDataTable);
- DataRow myNewDataRow = myDataTable.NewRow();
- 代码解释
- 第一行是调用 DataTable 的 NewRow()来创建一个 新 row。
- 第二至四行,是为该行的各个列补充值。
- 第五行,调用 Rows 的 Add() 把该列加到 行集合 中。
- 第六行,调用 Adapter 的 Update() 函数 完成添加的操作。
- 代码实例
- 如何修改 DataTable 中的 DataRow
- 代码实例
- myDataTable.PrimaryKey = new DataColumn[] { myDataTable.Columns["CustomerID"]
DataRow myEditDataRow = myDataTable.Rows.Find("J5COM");myEditDataRow["CompanyName"] = "Widgets Inc.";
myEditDataRow["Address"] = "1 Any Street";
int numOfRows = mySqlDataAdapter.Update(myDataTable);
- myDataTable.PrimaryKey = new DataColumn[] { myDataTable.Columns["CustomerID"]
- 代码解释
- 在修改 DataRow 前,首先要确保 DataTable 已经设置了 PrimaryKey 。(注意:这一步通常应该是在 Adapter 调用了 Fill()后做的 )
- 使用 DataTable.Rows.Find 函数来找出符合条件的行。
- 对 DataRow 做出修改,
- 调用 Adapter 的 Update() 来把修改写入数据库。
- 对于修改 DataRow,可以调用 BeginEdit() 和 EndEdit()/ CancelEdit() 来标志 修改的开始 和 终结。
- 代码实例
- 如何删除 DataTable 中的 DataRow
- 与上述“如何修改 DataTable 中的 DataRow”,唯一不同的是在 Find之后,调用 DataRow 的 Delete()来删除行。
- 与 修改 相关的 event
- 如何更新(Update)数据
- 如何处理 Update Failure
- 各种处理机制
- 机制一:在发生错误时马上停止之后的所有操作。
- 机制二:发生错误后,仍然继续之后的无错误操作;在处理完成后,才整体地检查update过程中发生了什么错误。
- 机制二的实现
- 代码实例
- mySqlDataAdapter.ContinueUpdateOnError = true;
if (myDataSet.HasErrors)
{
foreach (DataTable myDataTable in myDataSet.Tables)
{
if (myDataTable.HasErrors)
{
foreach (DataRow myDataRow in myDataTable.Rows)
{
if (myDataRow.HasErrors)
{
Console.WriteLine(myDataRow.RowError);
foreach (DataColumn myDataColumn in myDataTable.Columns)
{
Console.WriteLine(myDataColumn + " original value = " +
myDataRow[myDataColumn, DataRowVersion.Original]);
Console.WriteLine(myDataColumn + " current value = " +
myDataRow[myDataColumn, DataRowVersion.Current]);
} } } } } }
- mySqlDataAdapter.ContinueUpdateOnError = true;
- 代码解释
- 如果将 ContinueUpdateOnError 设置为 true,则在更新行过程中遇到错误时不引发异常。跳过该行的更新,并将错误信息置于出错行的 RowError 属性中。DataAdapter 继续更新后面的行。
如果将 ContinueUpdateOnError 设置为 false,在更新行的过程中遇到错误时就会引发异常。
- DataSet,DataTable 和 DataRow 都有HasErrors 属性,以便检查是否在 update 过程中发生了错误。
- RowError 是一个描述错误的字符串。
- 如果将 ContinueUpdateOnError 设置为 true,则在更新行过程中遇到错误时不引发异常。跳过该行的更新,并将错误信息置于出错行的 RowError 属性中。DataAdapter 继续更新后面的行。
- 代码实例
- 各种处理机制
- 如何在 DataSet 中使用 Transaction
- 代码实例
- SqlTransaction mySqlTransaction = mySqlConnection.BeginTransaction();
mySqlDataAdapter.SelectCommand.Transaction = mySqlTransaction;
mySqlDataAdapter.InsertCommand.Transaction = mySqlTransaction;
mySqlDataAdapter.UpdateCommand.Transaction = mySqlTransaction;
mySqlDataAdapter.DeleteCommand.Transaction = mySqlTransaction;
mySqlDataAdapter.Update(myDataSet);
mySqlTransaction.Commit();
- SqlTransaction mySqlTransaction = mySqlConnection.BeginTransaction();
- 代码解释
- 先建立一个 SqlTransaction 对象,然后把 它 传递给 各个有关的 Command(无关的应该不用吧)。
- 在 update之后,必须 Commit;否则,默认的 动作是 Rollback。
- 代码实例