Доступ к удаленным строкам из DataTable - PullRequest
7 голосов
/ 26 апреля 2010

У меня есть родительская WinForm, которая имеет MyDataTable _dt в качестве члена. Тип MyDataTable был создан в инструменте конструктора «Набор типизированных данных» в Visual Studio 2005 (MyDataTable наследует от DataTable) _dt заполняется из БД через ADO.NET. Основываясь на изменениях в пользовательском взаимодействии в форме, я удаляю строку из таблицы следующим образом:

_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 ]

14 голосов
/ 26 апреля 2010

Метод Delete отмечает строку для удаления; строка фактически не удаляется, пока вы не позвоните AcceptChanges.

Вместо этого позвоните _dt.Rows.Remove(_dt.FindBySomeKey(_someKey)), что также примет изменение.
Верьте или нет, Rows.Remove полностью удалит строку, тогда как row.Delete() не будет .
Обратите внимание: если вы вызовете Rows.Remove, строка будет удалена навсегда и не будет удалена из базы данных адаптером данных.

В 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())
{
    ...

EDIT

Вот версия 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); }
}
4 голосов
/ 03 ноября 2012

То, что вы делаете, чтобы пропустить строки в вашей итерации, является правильным, я обычно проверяю RowState, когда перебираю DataTable, который может быть изменен.

В некоторых случаях я считаю, что вы хотите, чтобы исходное значение строки было отмечено до удаления строки. Существует опция вторичного индекса при извлечении определенного значения datarow.

string st = dr["columnname", DataRowVersion.Original].ToString(); // c#

dim st As String = dr("columnname", DataRowVersion.Original).ToString() ' vb.net

Я застрял на этом несколько раз в прошлом.

Что касается метода GetChanges (RowState), не забудьте проверить наличие нулевого возврата. Если строк этого RowState нет, возвращаемая переменная DataTable равна нулю (думаю, она должна вернуть таблицу с ноль строк)

2 голосов
/ 26 апреля 2010

Вам нужно будет проверить:

 _dt.DefaultView.RowStateFilter

Я думаю, что настройка по умолчанию не будет показывать удаленные строки, может быть, вы где-то измените это.

Вы всегда можете создать дополнительный RowView, управлять его фильтром и выполнять цикл по представлению.

1 голос
/ 26 апреля 2010

Использовать GetChanges ():

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

Если вы хотите получить все добавленные и измененные, используйте побитовое ИЛИ при добавлении и изменении:

foreach (myDataTableRow row in
    _dt.GetChanges(DataRowState.Added | DataRowState.Modified))
{
    sbFilter.Append("'" + row.info + "',");
}
0 голосов
/ 26 апреля 2010

Я не уверен в этом, но я думаю, что если вы вызовете _dt.AcceptChanges() после удаления одной или нескольких строк, вы не "увидите" удаленные строки, когда будете выполнять итерацию по коллекции строк в таблицах данных.

...