从DataTable访问已删除的行

时间:2010-04-26 14:19:25

标签: c# .net datatable c#-2.0

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

_dt.FindBySomeKey(_someKey).Delete();

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

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

问题是在删除后执行此操作时,会抛出以下异常: 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()方法标记的行?

5 个答案:

答案 0 :(得分:14)

Delete method标记要删除的行;在您致电AcceptChanges之前,该行实际上并未删除。

而是拨打_dt.Rows.Remove(_dt.FindBySomeKey(_someKey)),这也会接受更改 信不信由你,Rows.Remove will completely remove the row, whereas row.Delete() won't 请注意,如果您致电Rows.Remove,该行将永久消失,并且不会被DataAdapter从数据库中删除。

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

///<summary>Gets the rows in a typed DataTable that have not been deleted.</summary>
public static EnumerableRowCollection<TRow> CurrentRows<TRow>(this TypedTableBase<TRow> 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<TRow> CurrentRows(IEnumerable<TRow> 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<MyRow> CurrentRows() { return Utils.CurrentRows(this); }
}

答案 1 :(得分:3)

您在迭代中跳过行的操作是正确的,当我遍历可能被修改的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(我认为它应该返回一个表零行)

答案 2 :(得分:2)

你必须检查:

 _dt.DefaultView.RowStateFilter

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

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

答案 3 :(得分:1)

使用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 + "',");
}

答案 4 :(得分:0)

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