转自:http://blog.csdn.net/cui55/article/details/1371411
在 DataSet 中创建 DataTable 之后,您执行的活动可以与使用数据库中的表时执行的活动相同。您可以添加、查看、编辑和删除表中的数据;可以监视错误和事件;并且可以查询表中的数据。在修改 DataTable 中的数据时,您也可以验证更改是否正确,并决定是否以编程方式接受更改或拒绝更改。
本节内容
将数据添至表中:说明如何创建新行并将其添至表中。
在创建 DataTable 并使用列和约束定义其结构之后,您可以将新的数据行添至表中。要添加新行,可将一个新变量声明为 DataRow 类型。调用 NewRow 方法时,将返回新的 DataRow 对象。然后,DataTable 会根据表的结构按 DataColumnCollection 的定义创建 DataRow 对象。
以下示例演示了如何通过调用 NewRow 方法来创建新行。
DataRow workRow = workTable.NewRow();
然后您可以使用索引或列名来操作新添加的行,如下例所示。
workRow["CustLName"] = "Smith"; workRow[1] = "Smith";
在将数据插入新行后,Add 方法可用于将行添至 DataRowCollection,如以下代码所示。
workTable.Rows.Add(workRow);
您也可以通过传入值的数组(类型化为 Object),调用 Add 方法来添加新行,如下例所示。
workTable.Rows.Add(new Object[] {1, "Smith"});
将类型化为 Object 的值的数组传递到 Add 方法,可在表内创建新行并将其列值设置为对象数组中的值。请注意,数组中的值会根据它们在表中出现的顺序相继与各列匹配。
以下示例将十行添至新建的 Customers 表中。
DataRow workRow;
for (int i = 0; i <= 9; i++) { workRow = workTable.NewRow(); workRow[0] = i; workRow[1] = "CustName" + i.ToString(); workTable.Rows.Add(workRow); } |
查看表中数据:说明如何访问行中的数据,包括数据的原始版本和当前版本。
可以使用 DataTable 的 Rows 和 Columns 集合来访问 DataTable 中的内容。也可以根据包括搜索标准、排序顺序和行状态等特定标准,使用 DataTable.Select 方法返回 DataTable 中数据的子集。此外,用主键值搜索特定行时,还可使用 DataRowCollection 的 Find 方法。
DataTable 对象的 Select 方法返回一组与指定条件匹配的 DataRow 对象。Select 采用筛选表达式、排序表达式和 DataViewRowState 的可选参数。筛选表达式根据 DataColumn 值(例如 LastName = 'Smith' 。排序表达式遵循用于为列排序的标准 SQL 约定,例如 LastName ASC, FirstName ASC 。有关编写表达式的规则,请参阅DataColumn 类的 Expression 属性。
提示 如果您将对 DataTable 的 Select 方法执行多次调用,可通过先为 DataTable 创建 DataView来提高性能。创建 DataView 会为表中的行编制索引。然后,Select 方法会使用该索引,这样将显著缩短生成查询结果的时间。有关为 DataTable 创建 DataView 的信息,请参阅创建和使用 DataView。
Select 方法基于 DataViewRowState 确定要查看或操作的行的版本。下表说明了可能的 DataViewRowState 枚举值。
成员名称 |
说明 |
CurrentRows |
当前行,包括未更改的行、已添加的行和已修改的行。 |
Deleted |
已删除的行。 |
ModifiedCurrent |
当前版本,它是原始数据的修改版本(请参阅ModifiedOriginal)。 |
ModifiedOriginal |
所有已修改行的原始版本。使用 ModifiedCurrent 时,当前版本可用。 |
Added |
新行。 |
None |
无。 |
OriginalRows |
原始行,包括未更改的行和已删除的行。 |
Unchanged |
未更改的行。 |
在下面的示例中,DataSet 对象已经过筛选,这样,您可以只使用其 DataViewRowState 设置为 CurrentRows的行。
DataRow[] currRows = workTable.Select(null, null, DataViewRowState.CurrentRows);
if (currRows.Length < 1 ) Console.WriteLine("No Current Rows Found"); else { foreach (DataColumn myCol in workTable.Columns) Console.Write("/t{0}", myCol.ColumnName);
Console.WriteLine("/tRowState");
foreach (DataRow myRow in currRows) { foreach (DataColumn myCol in workTable.Columns) Console.Write("/t{0}", myRow[myCol]);
Console.WriteLine("/t" + myRow.RowState); } }
Select 方法可用于返回具有不同 RowState 值或字段值的行。以下示例返回一个引用所有已删除行的 DataRow数组,并返回另一个引用所有已排序行(按照 CustLName 排序,其中 CustID 列大于 5)的 DataRow 数组。
// Retrieve all deleted rows. DataRow[] delRows = workTable.Select(null, null, DataViewRowState.Deleted);
// Retrieve rows where CustID > 5, and order by CustLName. DataRow[] custRows = workTable.Select("CustID > 5", "CustLName ASC"); |
编辑表中的数据:说明如何修改行中的数据,包括挂起对行的更改,直至验证并接受了建议的更改。
当您在 DataRow 中更改列值时,所做更改会立即置于行的 Current 状态中。然后,RowState 会设置为Modified,并使用 DataRow 的 AcceptChanges 或 RejectChanges 方法来接受或拒绝所做更改。DataRow还提供了三种可用于在编辑行时将行的状态挂起的方法。这些方法是 BeginEdit、EndEdit 和 CancelEdit。
当您直接在 DataRow 中修改列值时,DataRow 会使用 Current、Default 和 Original 行版本来管理列值。除这些行版本以外,BeginEdit、EndEdit 和 CancelEdit 方法还使用第四个行版本:Proposed。
在执行编辑操作(通过调用 BeginEdit 开始,并且通过使用 EndEdit 或 CancelEdit 或者通过调用AcceptChanges 或 RejectChanges 结束)的过程中,Proposed 行版本会存在。
在编辑操作过程中,您可以通过计算 DataTable 的 ColumnChanged 事件中的 ProposedValue 来将验证逻辑应用于各列。ColumnChanged 事件保存 DataColumnChangeEventArgs,可保持对正在更改的列和ProposedValue 的引用。计算了建议值后,可以对其进行修改或取消编辑。编辑结束时,行从 Proposed 状态中移出。
您可以通过调用 EndEdit 来确认编辑,也可以通过调用 CancelEdit 来取消编辑。请注意,尽管 EndEdit 确实已确认您所做的编辑,但在调用 AcceptChanges 之前,DataSet 并没有实际接受更改。另外请注意,如果在EndEdit 或 CancelEdit 编辑结束之前调用 AcceptChanges,编辑将会终止,并接受 Current 和 Original 行版本的 Proposed 行值。调用 RejectChanges 会以同样的方式结束编辑,并放弃 Current 和 Proposed 行版本。在调用 AcceptChanges 或 RejectChanges 之后调用 EndEdit 或 CancelEdit 不会起作用,因为编辑已经结束。
以下示例演示了如何将 BeginEdit 与 EndEdit 和 CancelEdit 一起使用。本示例也会检查 ColumnChanged 事件中的 ProposedValue,并决定是否取消编辑。
DataTable workTable = new DataTable(); workTable.Columns.Add("LastName", typeof(String));
workTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
DataRow workRow = workTable.NewRow(); workRow[0] = "Smith"; workTable.Rows.Add(workRow);
workRow.BeginEdit(); // Causes the ColumnChanged event to write a message and cancel the edit. workRow[0] = ""; workRow.EndEdit();
// Displays "Smith, New". Console.WriteLine("{0}, {1}", workRow[0], workRow.RowState);
protected static void OnColumnChanged(Object sender, DataColumnChangeEventArgs args) { if (args.Column.ColumnName == "LastName") if (args.ProposedValue.ToString() == "") { Console.WriteLine("Last Name cannot be blank. Edit canceled."); args.Row.CancelEdit(); } } |
行状态与行版本:提供有关行的不同状态的信息。
ADO.NET 用行状态和版本管理表中的行。行状态表示行的状态。当修改行时,行版本会维护存储于行中的值,包括当前值、原始值和默认值。例如,修改了某行中的一列后,该行会有一个 Modified 的行状态,并且会存在两个行版本:Current(包含当前行值)和 Original(包含修改该列前的行值)。
每个 DataRow 对象都具有 RowState 属性,您可以检查此属性来确定行的当前状态。下表给出了对各RowState 枚举值的简要说明。
RowState |
说明 |
Unchanged |
自上次调用 AcceptChanges 之后,或自 DataAdapter.Fill 创建了行之后,未做出过任何更改。 |
Added |
已将行添至表中,但尚未调用 AcceptChanges。 |
Modified |
已更改了行的一些元素。 |
Deleted |
已将该行从表中删除,并且尚未调用 AcceptChanges。 |
Detached |
对于已经创建但不属于任何 DataRowCollection 的行,设置为 Detached。新建行的 RowState设置为 Detached。通过调用 Add 方法将新的 DataRow 添至 DataRowCollection 之后,RowState 属性的值设置为 Added。
对于已经使用 Remove 方法(或是在使用 Delete 方法之后使用了 AcceptChanges 方法)从DataRowCollection 中移除的行,也设置为 Detached。 |
在 DataSet、DataTable 或 DataRow 上调用 AcceptChanges 时,会移除行状态为 Deleted 的所有行。剩余的行会被赋予 Unchanged 行状态,并且 Original 行版本中的值会改写为 Current 行版本值。调用RejectChanges 时,会移除行状态为 Added 的所有行。剩余的行会被赋予 Unchanged 的行状态,并且Current 行版本中的值会改写为 Original 行版本值。
通过用列引用来传递 DataRowVersion 参数,您可以查看行的不同行版本,如下例所示。
DataRow custRow = custTable.Rows[0]; string custID = custRow["CustomerID", DataRowVersion.Original].ToString();
下表给出了各 DataRowVersion 枚举值的简要说明。
DataRowVersion |
说明 |
Current |
行的当前值。如果是有 Deleted 的 RowState 的行,则不存在此行版本。 |
Default |
特定行的默认行版本。Added、Modified 或 Unchanged 行的默认行版本是Current。Deleted 行的默认行版本是 Original。Detached 行的默认行版本是 Proposed。 |
Original |
行的原始值。如果是有 Added 的 RowState 的行,则不存在此行版本。 |
Proposed |
行的建议值。在对行进行编辑操作期间,或对于不属于 DataRowCollection 的行,存在此行版本。 |
通过调用 HasVersion 方法并将 DataRowVersion 作为参数传递,您可以测试 DataRow 是否具有特定的行版本。例如,在调用 AcceptChanges 之前,DataRow.HasVersion(DataRowVersion.Original) 对新添加的行将返回 false。
例如,以下代码示例显示了表中所有已删除行的值。已删除的行没有 Current 行版本,因此在访问列值时必须传递 DataRowVersion.Original。
DataTable catTable = catDS.Tables["Categories"];
DataRow[] delRows = catTable.Select(null, null, DataViewRowState.Deleted);
Console.WriteLine("Deleted rows:/n");
foreach (DataColumn catCol in catTable.Columns) Console.Write(catCol.ColumnName + "/t"); Console.WriteLine();
foreach (DataRow delRow in delRows) { foreach (DataColumn catCol in catTable.Columns) Console.Write(delRow[catCol, DataRowVersion.Original] + "/t"); Console.WriteLine(); } |
从表中删除行:说明如何从表中移除行。
用于从 DataTable 对象中删除 DataRow 对象的方法有两种:DataRowCollection 对象的 Remove 方法和DataRow 对象的 Delete 方法。Remove 方法从 DataRowCollection 中删除 DataRow,而 Delete 方法只将行标记为删除。当应用程序调用 AcceptChanges 方法时,才会发生实际的删除。通过使用 Delete,您可以在实际删除之前先以编程方式检查哪些行标记为删除。如果将行标记为删除,其 RowState 属性会设置为 Deleted。
在将 DataSet 或 DataTable 与 DataAdapter 和关系型数据源一起使用时,用 DataRow 的 Delete 方法移除行。Delete 方法只是在 DataSet 或 DataTable 中将行标记为 Deleted,而不会移除它。而 DataAdapter 在遇到标记为 Deleted 的行时,会执行其 DeleteCommand 以在数据源中删除该行。然后,就可以用AcceptChanges 方法永久移除该行。如果使用 Remove 删除该行,则该行将从表中完全移除,但DataAdapter 不会在数据源中删除该行。
DataRowCollection 的 Remove 方法采用 DataRow 作为参数,并将其从集合中移除,如下例所示。
workTable.Rows.Remove(workRow);
作为对比,以下示例演示了如何调用 DataRow 上的 Delete 方法来将其 RowState 改为 Deleted。
workRow.Delete();
如果将行标记为删除,并且调用 DataTable 对象的 AcceptChanges 方法,该行就会从 DataTable 中移除。相比之下,如果调用 RejectChanges,行的 RowState 就会恢复到被标记为 Deleted 之前的状态。
注意 如果 DataRow 的 RowState 是 Added,则意味着已将其添至表中,然后将其标记为Deleted,从表中移除。 |
添加和读取行错误信息:说明如何按行插入错误信息,以用于解决有关应用程序内行中数据的问题。
为了避免在编辑 DataTable 中的值时每次发生行错误都必须响应,可将错误信息添至行中,以便以后使用。DataRow 对象通过对各行提供 RowError 属性来支持此功能。将数据添至 DataRow 的 RowError 属性会将DataRow 的 HasErrors 属性标记为 true。如果 DataRow 是 DataTable 的组成部分,且 DataRow.HasErrors是 true,则 DataTable.HasErrors 属性也是 true。这也适用于 DataTable 所属的 DataSet。为错误做测试时,可以检查 HasErrors 属性以确定错误信息是否已添至所有行。如果 HasErrors 为 true,则可使用 DataTable 的GetErrors 方法以便只返回和检查有错误的行,如下例所示。
DataTable workTable = new DataTable("Customers"); workTable.Columns.Add("CustID", typeof(Int32)); workTable.Columns.Add("Total", typeof(Double));
workTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
for (int i = 0; i < 10; i++) workTable.Rows.Add(new Object[] {i, i*100});
if (workTable.HasErrors) { Console.WriteLine("Errors In Table " + workTable.TableName);
foreach (DataRow myRow in workTable.GetErrors()) { Console.WriteLine("CustID = " + myRow["CustID"]); Console.WriteLine(" Error = " + myRow.RowError + "/n"); } }
protected static void OnRowChanged(Object sender, DataRowChangeEventArgs args) { // Check for zero values. if (args.Row["Total"].Equals(0D)) args.Row.RowError = "Total cannot be 0."; } |
接受或拒绝对行的更改:说明如何接受或拒绝对行的更改。
在检验过对 DataTable 中的数据所做更改的准确性之后,可使用 DataRow、DataTable 或 DataSet 的AcceptChanges 方法来接受更改,此方法会将 Current 行值设置为 Original 值,并会将 RowState 属性设置为 Unchanged。接受或拒绝更改会清除所有 RowError 信息,并将 HasErrors 属性设置为 false。接受或拒绝更改还可以影响在数据源中更新数据。有关更多信息,请参阅使用 DataAdapter 和 DataSet 更新数据库。
如果 DataTable 上存在外键约束,使用 AcceptChanges 和 RejectChanges 接受或拒绝的更改就会根据ForeignKeyConstraint.AcceptRejectRule 传播至 DataRow 的子行。
以下示例检查有错误的行,在适用之处解决错误,拒绝无法解决错误的行。请注意,对于解决的错误,RowError值会重置为空字符串,导致将 HasErrors 属性设置为 false。当解决或拒绝了所有的有错误的行时,就会调用AcceptChanges 来接受对整个 DataTable 的所有更改。
if (workTable.HasErrors) {
foreach (DataRow errRow in workTable.GetErrors()) { if (errRow.RowError == "Total cannot exceed 1000.") { errRow["Total"] = 1000; errRow.RowError = ""; // Clear the error. } else errRow.RejectChanges(); } }
workTable.AcceptChanges(); |
处理 DataTable 事件:提供可用于 DataTable 的事件的相关信息,包括修改列值和添加或删除行时的事件。
DataTable 对象提供一系列可由应用程序处理的事件。下表说明了 DataTable 事件。
事件 |
说明 |
ColumnChanged |
在值已成功插入列时发生。 |
ColumnChanging |
在已提交列值时发生。 |
RowChanged |
在已成功编辑表中的行后发生。 |
RowChanging |
当正在更改表中的行时发生。 |
RowDeleted |
在表中的某行已被标记为 Deleted 之后发生。 |
RowDeleting |
在表中的某行被标记为 Deleted 之前发生。 |
以下示例创建 4 个事件:OnColumnChanged、OnColumnChanging、OnRowChanged 和OnRowChanging。这些事件中的每一个都在列或行更改时发生。
workTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged); workTable.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging); workTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged); workTable.RowChanging += new DataRowChangeEventHandler(OnRowChanging);
protected static void OnColumnChanged(object sender, DataColumnChangeEventArgs args) { Console.Write(" ColumnChanged: "); Console.Write(args.Column.ColumnName + " changed to '" + args.ProposedValue + "'/n"); }
protected static void OnColumnChanging(object sender, DataColumnChangeEventArgs args) { Console.Write("ColumnChanging: "); Console.Write(args.Column.ColumnName + " equals '" + args.Row[args.Column] + "', changing to '" + args.ProposedValue + "'/n"); }
protected static void OnRowChanging(object sender, DataRowChangeEventArgs args) { if (args.Action != DataRowAction.Nothing) Console.WriteLine(" RowChanging: Action = " + args.Action + ", CustID = " + args.Row["CustID"]); }
protected static void OnRowChanged(object sender, DataRowChangeEventArgs args) { if (args.Action != DataRowAction.Nothing) Console.WriteLine(" RowChanged: Action = " + args.Action + ", CustID = " + args.Row["CustID"]); } |
posted on 2014-06-30 11:08
Ke 阅读(2598)
评论(0) 编辑 收藏 所属分类:
C#