Benutzer mit den meisten Antworten
LINQ-Abfrage mit geschachtelter Gruppierung in VB.NET

Frage
-
Hallo alle zusammen.
Ich benötige in Visual Studio 2013 mit VB.NET eine mehrfach gruppierte LINQ-Abfrage auf eine ADO-Tabelle, die etwa so aussehen sollte:
Dim Peoples = Ppls.Table.AsEnumerable() ' ADO Dim SomePeople = Ppls.OrderBy(Function(p) p("ID")). OrderBy(Function(p) p("NAME2")). OrderBy(Function(p) p("NAME")). GroupBy(Function(p) p("TOWN")). GroupBy(Function(n) n("NAME")) For Each peopleGroup In SomePeople Console.WriteLine("Town : {0}", peopleGroup.Key) For Each place In peopleGroup Console.WriteLine("Peoples with name {0}:", place("NAME")) For Each people In place Console.WriteLine("Name {0} (ID = {1})", people("NAME2"), people("ID")) Next Next Next
Damit sollte die Ausgabe etwa so aussehen:
Town: London
Peoples with Name Broke:
Name Glen (ID = 282344)
Name Irene (ID = 523121)
Name Oscar (ID = 851234)
Peoples with Name Wilde:
Name Oscar (ID = 354321)
Name Paul (ID = 769081)
Peoples with Name ...
Town: Birmingham
Peoples with Name Glendel:
Name Michael (ID = 625314)
...
Die LINQ-Anweisung
Dim SomePeople = Peoples.OrderBy(Function(p) p("ID")). OrderBy(Function(p) p("NAME2")). OrderBy(Function(p) p("NAME")). GroupBy(Function(p) p("TOWN")). GroupBy(Function(p) p("NAME"))
dürfte vermutlich auch so aussehen:
Dim SomePeople = Ppls.OrderBy(Function(p) p("ID")). OrderBy(Function(p) p("NAME2")). OrderBy(Function(p) p("NAME")). GroupBy(Function(p) p("TOWN"), Function(p) p("NAME"))
Leider funktioniert es so nicht, weil in der Anweisung
Console.WriteLine("Peoples with name {0}:", place("NAME"))
für "place('Name')" wegen "Option strict on" ein spätes Binden nicht zugelassen ist, was aber sicher auch nicht die eigentliche Fehlerursache sein dürfte, und in der Anweisung
For Each people In place
ist der Ausdruck "place" vom Typ Object und keine Auflistung.
Ich weiß gar nicht mehr, was ich schon alles versucht habe, die Typen anzupassen, sowohl in der LINQ-Anweisung (Of ...) als auch in den For Each-Schleifen (As ...). Leider ist es mir nicht gelungen, die Fehler zu beseitigen. Vermutlich ist es ganz einfach und ich denke nur zu kompliziert ... oder das Brett vor meinem Kopf ist zu groß...
Für eine Lösung oder wenigstens einen verwertbaren Denkanstoß wäre ich erfreut und sehr dankbar.
Antworten
-
Hi,
ich würde das mit 2 LinQ-Ausdrücken lösen, z.B. so:Module Module01 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.Write(ex.ToString) End Try Console.Write("weiter mit Taste") Console.ReadKey() End Sub Class Demo Friend Sub Execute() Dim dt As New DataTable With dt With .Columns .Add("ID", GetType(Integer)) .Add("NAME2", GetType(String)) .Add("NAME", GetType(String)) .Add("TOWN", GetType(String)) End With With .Rows .Add(523121, "Irene", "Broke", "London") .Add(769081, "Paul", "Wilde", "London") .Add(282344, "Glen", "Broke", "London") .Add(625314, "Michael", "Glendel", "Birmingham") .Add(354321, "Oscar", "Wilde", "London") .Add(851234, "Oscar", "Broke", "London") End With .AcceptChanges() End With Dim Peoples = dt.AsEnumerable() ' ADO For Each peopleGroup In Peoples.GroupBy(Function(p) p("TOWN")) Console.WriteLine("Town : {0}", peopleGroup.Key) For Each place In peopleGroup.GroupBy(Function(p) p("NAME")) Console.WriteLine("Peoples with name {0}:", place.Key) For Each people In place Console.WriteLine("Name {0} (ID = {1})", people("NAME2"), people("ID")) Next Next Next End Sub End Class End Module
--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 1. Juni 2017 07:47
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 9. Juni 2017 10:01
Alle Antworten
-
Hi,
ich würde das mit 2 LinQ-Ausdrücken lösen, z.B. so:Module Module01 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.Write(ex.ToString) End Try Console.Write("weiter mit Taste") Console.ReadKey() End Sub Class Demo Friend Sub Execute() Dim dt As New DataTable With dt With .Columns .Add("ID", GetType(Integer)) .Add("NAME2", GetType(String)) .Add("NAME", GetType(String)) .Add("TOWN", GetType(String)) End With With .Rows .Add(523121, "Irene", "Broke", "London") .Add(769081, "Paul", "Wilde", "London") .Add(282344, "Glen", "Broke", "London") .Add(625314, "Michael", "Glendel", "Birmingham") .Add(354321, "Oscar", "Wilde", "London") .Add(851234, "Oscar", "Broke", "London") End With .AcceptChanges() End With Dim Peoples = dt.AsEnumerable() ' ADO For Each peopleGroup In Peoples.GroupBy(Function(p) p("TOWN")) Console.WriteLine("Town : {0}", peopleGroup.Key) For Each place In peopleGroup.GroupBy(Function(p) p("NAME")) Console.WriteLine("Peoples with name {0}:", place.Key) For Each people In place Console.WriteLine("Name {0} (ID = {1})", people("NAME2"), people("ID")) Next Next Next End Sub End Class End Module
--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 1. Juni 2017 07:47
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 9. Juni 2017 10:01
-
Hallo Peter,
vielen Dank erst einmal für Deine Mühe.
Ja, so geht es.
Wie Du an dem an Haaren herbeigezogenen Beispiel vielleicht gemerkt hast, ging es mir aber um mehr, mehr um einen Grundsatz.
Zunächst möchte ich mit der Extension Method-Syntax die Übersichtlichkeit kurz und prägnant halten, sozusagen auf einen Blick, auch wenn das mit Function(irgendetwas) in VB.NET nicht ganz so elegant ist wie in C#.
Außerdem hege ich die Hoffnung, mit dem Variieren von OrderBy und GroupBy die Zugriffszeiten durch Beeinflussung des Sortierungszeitpunkts in Abhängigkeit der konkreten Schachtelungstiefe und -reihenfolge gering halten zu können. Ohne über die Sinnhaftigkeit der konkreten folgenden Anweisungen nachgedacht zu haben, meine ich das etwa so:
Dim SomePeople = Peoples.Select(Function(p) New With {p("ZIP"), p("TOWN"), p("AREA"), p("ID"), p("NAME"), p("NAME2"), p("BIRTHDAY")}). OrderBy(Function(p) p("TOWN")). GroupBy(Function(p) p("TOWN")). OrderBy(Function(p) p("ID")). OrderBy(Function(p) p("NAME2")). OrderBy(Function(p) p("NAME")). GroupBy(Function(p) p("NAME"))
oder so
Dim SomePeople = Peoples.Select(Function(p) New With {p("ZIP"), p("TOWN"), p("AREA"), p("ID"), p("NAME"), p("NAME2"), p("BIRTHDAY")}). OrderBy(Function(p) p("TOWN")). GroupBy(Function(p) p("TOWN")). GroupBy(Function(p) p("NAME")). OrderBy(Function(p) p("ID")). OrderBy(Function(p) p("NAME2")). OrderBy(Function(p) p("NAME"))
oder wie auch immer.
Wenn ich keinen Denkfehler habe und z.B. die Gruppen geordnet bearbeiten möchte, will ich vermeiden, die gesamte Tabelle oder Abfrage erst nach einem oder mehreren Schlüsseln zu ordnen bzw. umzuordnen. Zumindest auf oberster Ebene sollte das aus meiner jetzigen Sicht einen Zeitvorteil bringen, wenn ich also im Beispiel nicht erst die gesamte Tabelle sondern nur die Gruppen nach deren Schlüssel ordne (wenn damit nicht intern ohnehin zunächst erst einmal die gesamte Tabelle geordnet wird, was ich beinahe ahne... :-(( ).
Mir wäre also die Extension Method-Syntax lieber, schon wegen der Übersichtlichkeit. Es muss auch so gehen! Es ist sicher nur eine Frage der Typisierung.
Viele Grüße, Werner
WM