Próbuję wykonać zapytanie LINQ na obiekcie DataTable i dziwnie stwierdzam, że wykonywanie takich zapytań na DataTables nie jest proste. Na przykład:
var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;
To jest niedozwolone. Jak mogę uzyskać coś takiego?
Dziwi mnie, że zapytania LINQ nie są dozwolone w tabelach danych!
Odpowiedzi:
Nie można kwerendy przeciwko
DataTable
„s Wiersze kolekcji, ponieważDataRowCollection
nie realizujeIEnumerable<T>
. Musisz użyćAsEnumerable()
rozszerzenia dlaDataTable
. Tak jak:I jak mówi @Keith , musisz dodać odwołanie do System.Data.DataSetExtensions
AsEnumerable()
zwracaIEnumerable<DataRow>
. Jeśli chcesz przekonwertowaćIEnumerable<DataRow>
na aDataTable
, użyjCopyToDataTable()
rozszerzenia.Poniżej znajduje się zapytanie z wyrażeniem Lambda,
źródło
using System.Data;
myDataTable.Rows
zamiast tego, jak sugerował @JoelFan.myDataTable.Rows
jest to, żemyRow
zmienna jest jawnie rzutowana naDataRow
. Po skompilowaniu zapytanie jest przepisywane namyDataTable.Rows.Cast<DataRow>().Where(myRow => (int)myRow["RowNo"] == 1)
. Osobiście nie uważam, że wezwanie doAsEnumerable()
czegoś bardziej skomplikowanego niż wezwanie doCast<DataRow>()
. O ile mi wiadomo, wydajność jest taka sama, więc jest to tylko kwestia preferencji.źródło
(int)myRow["RowNo"]
formularzem ogólnym,myRow.Field<int>("RowNo")
aby wygodniej obsługiwać typy zerowalne.Nie chodzi o to, że celowo nie były dozwolone w DataTables, po prostu DataTables wcześniej niż IQueryable i ogólne IEnumerable konstrukcje, na których można wykonywać zapytania Linq.
Oba interfejsy wymagają pewnego rodzaju weryfikacji bezpieczeństwa typu. Tabele danych nie są mocno wpisane. Jest to ten sam powód, dla którego ludzie nie mogą na przykład zapytać o ArrayList.
Aby Linq działał, musisz zmapować swoje wyniki względem obiektów bezpiecznych dla typu i zapytać w zamian.
źródło
Jak powiedział @ ch00k:
Musisz także dodać odwołanie do projektu
System.Data.DataSetExtensions
źródło
myRow
lub użyjeszCast<DataRow>()
goRows
. Lepszy w użyciuAsEnumerable()
.System.Linq
aSystem.Data.DataSetExtensions
następniemyDataTable.Rows
zwraca wymienną kolekcjęDataRow
. To mogło się zmienić, minęło dziesięć lat, odkąd go użyłem.DataSet
rozszerzenia nie znalazły się w .NET Core lub .NET Standard, były już nieaktualne, kiedy opublikowałem tę odpowiedź. Naprawdę nie używałbymDataSet
w nowych projektach, istnieją znacznie lepsze modele dostępu do danych, zarówno pod względem łatwości kodowania, jak i wydajności.DataRowCollection
nie implementująIEnumerable<T>
po prostuIEnumerable
i dlatego nie działają z silnie wpisanym LINQ.pola nazwy i wieku są teraz częścią obiektu zapytania i można uzyskać do nich dostęp w następujący sposób: Console.WriteLine (query.name);
źródło
MessageBox.Show(name)
jest niezdefiniowany.Zdaję sobie sprawę, że kilkakrotnie na to odpowiedziano, ale aby zaoferować inne podejście:
Lubię używać tej
.Cast<T>()
metody, pomaga mi to zachować zdrowy rozsądek, widząc wyraźny typ zdefiniowany głęboko i myślę,.AsEnumerable()
że i tak go nazywa:lub
Jak zauważono w komentarzach, żadne inne zespoły nie są potrzebne, ponieważ jest to część Linq (Materiały referencyjne )
źródło
Używanie LINQ do manipulowania danymi w DataSet / DataTable
źródło
System.Data.DataSetExtensions
.źródło
Wypróbuj tę prostą linię zapytania:
źródło
Możesz użyć LINQ do obiektów w kolekcji Rows, na przykład:
źródło
DataTable.Rows
nie implementujeIEnumerable
, nie widzę, jak to zapytanie mogłoby się skompilować.Jest to prosty sposób, który działa dla mnie i wykorzystuje wyrażenia lambda:
Jeśli chcesz konkretną wartość:
źródło
Spróbuj tego
źródło
Najprawdopodobniej klasy dla DataSet, DataTable i DataRow są już zdefiniowane w rozwiązaniu. W takim przypadku nie będzie potrzebne odwołanie do DataSetExtensions.
Dawny. Nazwa klasy DataSet-> CustomSet, nazwa klasy DataRow-> CustomTableRow (ze zdefiniowanymi kolumnami: RowNo, ...)
Lub (jak wolę)
źródło
źródło
W mojej aplikacji stwierdziłem, że użycie LINQ do zestawów danych z rozszerzeniem AsEnumerable () dla DataTable, jak sugerowano w odpowiedzi, było bardzo wolne. Jeśli chcesz zoptymalizować szybkość, skorzystaj z biblioteki Json.Net Jamesa Newtonkinga ( http://james.newtonking.com/json/help/index.html )
źródło
System.Data.DataRow
przedmiotów. Serializowana i analizowana tabela danych tworzy lekkie dane składające się tylko z nazw kolumn i wartości każdego wiersza. Po uruchomieniu zapytania ładuje dane do pamięci, co w przypadku dużego zestawu danych może wymagać wymiany. Czasami narzut związany z kilkoma operacjami jest mniejszy niż narzut związany z kopiowaniem dużych ilości danych do i z pamięci.W przypadku VB.NET Kod będzie wyglądał następująco:
źródło
źródło
Przykład, jak to osiągnąć, podany poniżej:
źródło
Spróbuj tego...
źródło
Możesz sprawić, aby działał elegancko za pośrednictwem linq w następujący sposób:
Lub jak dynamiczny linq to (AsDynamic jest wywoływany bezpośrednio w DataSet):
Wolę ostatnie podejście, podczas gdy jest najbardziej elastyczne. PS: Nie zapomnij połączyć
System.Data.DataSetExtensions.dll
odniesieniaźródło
możesz spróbować, ale musisz mieć pewność, że typ wartości dla każdej kolumny
źródło
Proponuję następujące rozwiązanie:
Patrząc na dokumentację DataView , pierwszą rzeczą, którą możemy zobaczyć, jest:
Z tego, co otrzymuję, jest to, że DataTable służy wyłącznie do przechowywania danych, a DataView umożliwia nam „zapytanie” względem DataTable.
Oto jak to działa w tym konkretnym przypadku:
Próbujesz zaimplementować instrukcję SQL
w „języku DataTable”. W C # czytamy to w ten sposób:
który wygląda w C # w ten sposób:
źródło
źródło