2009-10-19 19 views
35

Jestem zaangażowany w proces uczenia C# i idzie dobrze jak dotąd. Ja jednak właśnie uderzyłem w moje pierwsze "co mówisz?" za chwilę.DataTable, Jak warunkowo usunąć wiersze

DataTable oferuje losowy dostęp do wiersza kolekcji Rows, nie tylko poprzez typowe zachowanie kolekcji, ale także poprzez DataTable.Select. Jednak nie wydaje się być w stanie powiązać tę zdolność z DataRow.Delete. Do tej pory wydaje mi się, że muszę to zrobić, aby warunkowo usunąć jeden lub więcej wierszy z tabeli.

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(); 

Ale nie jestem zadowolony z tego kodu. Nie jestem przekonany. Muszę czegoś przegapić. Czy naprawdę muszę sekwencyjnie uderzać w kolekcję wierszy, jeśli muszę warunkowo usunąć jeden lub więcej wierszy?

(nie przeszkadza odwrócony o. Ja usuwając z końcem DataTable. Więc to jest ok)

Odpowiedz

66

Można zapytania zestawu danych, a następnie pętli wybrane wiersze, aby ustawić je jako kasowania.

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

... i można także utworzyć kilka metod rozszerzenie, aby ułatwić ...

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(); 
} 
+0

Ach! Nie zdarzyło mi się, że Select() zwróciłby odwołanie do wierszy z danymi. Wiedziałem, że czegoś brakuje. Wielkie dzięki! –

+0

Zbyt dobre rozwiązanie, to również rozwiązało mój problem z datatable.select zmieniając zamówienie. – Signcodeindie

+0

Doskonałe rozwiązanie Matthew – Ravia

8

Nie mam windows box poręczny, aby spróbować tego, ale myślę, że można użyć DataView i zrób coś takiego:

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(); 
} 

Nie testowałem tego. Możesz spróbować.

+0

Próbowałem i zadziałało. Wolę jednak podejście Select. Ale warto o tym pamiętać. Dzięki :) +1 –

35

Oto jeden-liner przy użyciu LINQ i unikając oceny run-time z wybranych ciągów: metodę

someDataTable.Rows.Cast<DataRow>().Where(
    r => r.ItemArray[0] == someValue).ToList().ForEach(r => r.Delete()); 
+1

Naprawdę podobało mi się to rozwiązanie - bardzo ładne - Dzięki! – MDV2000

+2

Kiedyś zapamiętaj funkcję call someDataTable.AcceptChanges(); po usunięciu –

+1

@GreyWolf, jeśli chcesz zapisać zmiany z powrotem do bazy danych, NIE dzwoń do AcceptChanges! AcceptChanges zaznaczy wszystkie nowe/zaktualizowane wiersze jako niezmienione, w ten sposób DataAdapter będzie myślał, że nie ma żadnych zmian i nie zapisuje niczego do bazy danych na .Update(). –

0

Extension oparciu o 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(); 
} 

Następnie użyj:

DataTable dt = GetSomeData(); 
dt.DeleteRows(r => r.Field<double>("Amount") > 123.12 && r.Field<string>("ABC") == "XYZ"); 
Powiązane problemy