从DataTable访问已删除的行

我有一个父MyForm有一个MyDataTable _dt作为成员。 MyDataTable类型是在Visual Studio 2005中的“类型化数据集”设计器工具中创建的(MyDataTableinheritance自DataTable) _dt通过ADO.NET从db填充。 根据表单中用户交互的变化,我从表中删除一行,如下所示:

_dt.FindBySomeKey(_someKey).Delete();

稍后, _dt按值传递给对话框表单。 从那里,我需要扫描所有行来构建一个字符串:

  foreach (myDataTableRow row in _dt) { sbFilter.Append("'" + row.info + "',"); } 

问题是在删除后执行此操作时,会抛出以下exception: DeletedRowInaccessibleException: Deleted row information cannot be accessed through the row.

我目前正在使用的工作(感觉就像一个黑客)如下:

  foreach (myDataTableRow row in _dt) { if (row.RowState != DataRowState.Deleted && row.RowState != DataRowState.Detached) { sbFilter.Append("'" + row.info + "',"); } } 

我的问题:这是正确的方法吗? 为什么foreach循环访问通过Delete()方法标记的行?

你必须检查:

  _dt.DefaultView.RowStateFilter 

我认为默认设置不会显示已删除的行,也许你会在某处更改它。

您始终可以创建一个额外的RowView并控制其filter并在View上循环。

Delete方法标记要删除的行; 在调用AcceptChanges之前,实际上不会删除该行。

相反,调用_dt.Rows.Remove(_dt.FindBySomeKey(_someKey)) ,它也将接受更改。
信不信由你, Rows.Remove将完全删除行,而row.Delete()则不会 。 请注意,如果您调用Rows.Remove ,该行将永久消失,并且不会被DataAdapter从数据库中删除。

在C#3中,您可以使用以下扩展方法替换if语句:

 ///Gets the rows in a typed DataTable that have not been deleted. public static EnumerableRowCollection CurrentRows(this TypedTableBase table) where TRow : DataRow { return table.Where(r => r.RowState != DataRowState.Deleted); } foreach (myDataTableRow row in _dt.CurrentRows()) { ... 

编辑

这是一个C#2版本:

 static class Utils { public static IEnumerable CurrentRows(IEnumerable table) where TRow : DataRow { foreach(TRow row in table) { if (row.RowState != DataRowState.Deleted) yield return row; } } } foreach (myDataTableRow row in Utils.CurrentRows(_dt)) { 

您还可以将此函数放在类型表的分部类中:

 partial class MyTable { public IEnumerable CurrentRows() { return Utils.CurrentRows(this); } } 

你在迭代中跳过行所做的是正确的,当我循环遍历可能被修改的DataTable时,我会定期检查RowState。

在某些情况下,我认为您希望行被标记为已删除之前的原始行值。 检索特定数据行值时,有一个辅助索引选项。

 string st = dr["columnname", DataRowVersion.Original].ToString(); // c# dim st As String = dr("columnname", DataRowVersion.Original).ToString() ' vb.net 

我过去曾多次坚持过这个问题。

就GetChanges(RowState)方法而言,不要忘记检查null返回,如果没有该RowState的行,则返回的DataTable为null(我认为它应该返回一个零行的表)

使用GetChanges():

 foreach (myDataTableRow row in _dt.GetChanges(DataRowState.Added)) { sbFilter.Append("'" + row.info + "',"); } 

如果要全部添加和修改,请在添加和修改时使用按位OR:

 foreach (myDataTableRow row in _dt.GetChanges(DataRowState.Added | DataRowState.Modified)) { sbFilter.Append("'" + row.info + "',"); } 

我不确定这一点,但我认为如果在删除一行或多行后调用_dt.AcceptChanges() ,则在遍历数据表的Rows集合时,您将不会“看到”已删除的行。