DataTable, как условно удалить строки

Я занимаюсь изучением C #, и пока все идет хорошо. Однако я только сейчас ударил свое первое "что сказать?" момент.

DataTable предлагает произвольный доступ к своей коллекции Rows не только через типичное поведение коллекций, но и через DataTable.Select. Однако я не могу связать эту способность с DataRow.Delete. Пока что мне кажется, что это то, что мне нужно сделать, чтобы условно удалить одну или несколько строк из таблицы.

int max = someDataTable.Rows.Count - 1;
for(int i = max; i >= 0; --i)
{
    if((int)someDataTable.Rows[i].ItemArray[0] == someValue)
    {
        someDataTable.Rows[i].BeginEdit();
        someDataTable.Rows[i].Delete();
    }
    else
        break;
}
someDataTable.AcceptChanges();

Но меня этот код не устраивает. Я тоже не уверен. Я, должно быть, что-то упускаю. Неужели я действительно вынужден последовательно обращаться к коллекции строк, если мне нужно удалить одну или несколько строк по условию?

(не обращайте внимания на перевернутое for. Я удаляю с конца таблицы данных. Так что все в порядке)


person Alexandre Bell    schedule 19.10.2009    source источник


Ответы (4)


Вы можете запросить набор данных, а затем зациклить выбранные строки, чтобы установить их как удаляемые.

var rows = dt.Select("col1 > 5");
foreach (var row in rows)
    row.Delete();

... и вы также можете создать несколько методов расширения, чтобы упростить работу ...

myTable.Delete("col1 > 5");

public static DataTable Delete(this DataTable table, string filter)
{
    table.Select(filter).Delete();
    return table;
}
public static void Delete(this IEnumerable<DataRow> rows)
{
    foreach (var row in rows)
        row.Delete();
}
person Matthew Whited    schedule 20.10.2009
comment
Ах! Мне не приходило в голову, что Select () вернет ссылку на строки данных. Я знал, что мне что-то не хватает. Огромное спасибо! - person Alexandre Bell; 20.10.2009
comment
Слишком хорошее решение, это также решило мою проблему datatable.select, изменив порядок. - person Signcodeindie; 30.03.2012
comment
Наконец, вы хотите применить эти изменения к таблице dt, используя команду ниже. - person Damith; 24.12.2013

Вот однострочник, использующий LINQ и избегающий любой оценки выбранных строк во время выполнения:

someDataTable.Rows.Cast<DataRow>().Where(
    r => r.ItemArray[0] == someValue).ToList().ForEach(r => r.Delete());
person Alain    schedule 07.05.2012
comment
Мне очень понравилось это решение - очень хорошее - Спасибо! - person MDV2000; 08.06.2012
comment
Иногда не забудьте вызвать функцию someDataTable.AcceptChanges (); после удаления - person Grey Wolf; 12.10.2013
comment
@GreyWolf, если вы хотите записать изменения обратно в базу данных, НЕ вызывайте AcceptChanges! AcceptChanges пометит все новые / обновленные строки как неизменные, поэтому DataAdapter будет думать, что изменений нет, и не будет ничего записывать в базу данных на .Update (). - person The Conspiracy; 10.11.2013
comment
что такое r.ItemArray [0] в данном случае, это первый столбец строки? отметьте меня, когда ответите. - person user3281466; 03.06.2015
comment
Это очень красивый и элегантный код. Искал эту уловку двое суток! И большое спасибо, @Alain, за публикацию этого кода, потому что ты спас мне день. - person noobprogrammer; 21.10.2019

У меня нет удобного окна Windows, чтобы попробовать это, но я думаю, вы можете использовать DataView и сделать что-то вроде этого:

DataView view = new DataView(ds.Tables["MyTable"]);
view.RowFilter = "MyValue = 42"; // MyValue here is a column name

// Delete these rows.
foreach (DataRowView row in view)
{
  row.Delete();
}

Однако я не проверял это. Вы можете попробовать.

person itsmatt    schedule 20.10.2009
comment
Я попробовал, и это сработало. Однако я предпочитаю подход Select. Но нужно иметь в виду. Спасибо :) +1 - person Alexandre Bell; 20.10.2009

Метод расширения на основе Linq

public static void DeleteRows(this DataTable dt, Func<DataRow, bool> predicate)
{
    foreach (var row in dt.Rows.Cast<DataRow>().Where(predicate).ToList())
        row.Delete();
}

Затем используйте:

DataTable dt = GetSomeData();
dt.DeleteRows(r => r.Field<double>("Amount") > 123.12 && r.Field<string>("ABC") == "XYZ");
person Sebastian Widz    schedule 08.04.2017