LINQ einmalig komplex

Die Überschrift wird google SEO nicht gefallen. Gesucht ist die Antwort auf die Frage: Wie frägt man mit LINQ in einer komplexen Liste (auch mit anonymen Typen) so ab, das doppelte Datensätze ausgeblendet werden. Anders formuliert Distinct.

Als Aufgabe soll eine Liste von Ländern in einer ASP.NET Dropdown Liste befüllt werden.

   1:  Dim co(3)
   2:  co(0) = New With {.Country = "Austria", .CountryID = 1, .Postal = 84489}
   3:  co(1) = New With {.Country = "Austria", .CountryID = 1, .Postal = 12345}
   4:  co(2) = New With {.Country = "Austria", .CountryID = 1, .Postal = 9876}
   5:  co(3) = New With {.Country = "Germany", .CountryID = 2, .Postal = 9876}
   6:   
   7:  Dim lander = From l In co
   8:                       Select l.Country
   9:                       Distinct
  10:  drp1.DataSource = lander
  11:  drp1.DataBind()

 

Das klappt ganz wunderbar, weil Country eine eindeutiges Kriterium darstellt. Wenn man nun zwei Werte aus der Liste selektiert wie die ID und den Wert erhält man ein komplexes Objekt, das intern über eine Identifier verwaltet wird. Wenn dieses Objekt streng typisiert ist, wird das Distinct keine eindeutigen Werte mehr finden, weil jedes Objekt einmalig ist, auch wenn die Werte der enthaltenen Eigenschaften zu 100% ident sind. Bei anonymen Objekten überschreibt der Compiler die Methoden Equals und GetHashCode um auf die realen Werte der Eigenschaften zu vergleichen.

Zunächst die noch funktionierende VB.NET Code Variante mit anonymen Objekten in der LINQ Query Liste.

   1:   Dim lander = From l In co
   2:                       Select l.Country, l.CountryID
   3:                       Distinct
   4:   drp1.DataSource = lander

Der Visual Studio 2015 debugger zeigt eine AnonymousType of Object Object Liste.

image

Derart gerüstet lässt der deklarative ASP.NET Webforms Code ganz einfach schreiben.

   1:    <asp:DropDownList  runat="server"
   2:              id="drp1" datatextfield="Country" DataValueField="CountryId"
   3:              ></asp:DropDownList>

 

Im nächsten Schritt denken wir über das moderne MVC ähnliche Modelbinding nach. Hier werden wir komplexere Informationen aus mehreren Feldern in der Dropdownliste anzeigen.

Hinweis: trotz VB.NET müssen die Eigenschaftsnamen im ASPX Code Case sensitiv korrekt geschrieben werden.

Dazu benötigt es streng typisierter Objekte, wie man zb mit folgenden Beispiel erzeugen könnte.

   1:  Dim lander = From l In co
   2:              Select New Adresse With {.Country = l.Country,
   3:                                       .CountryID = l.CountryID}
   4:             Distinct
   5:   
   6:   
   7:   
   8:  ...
   9:  Public Class Adresse
  10:      Public Country As String
  11:      Public CountryID As Integer
  12:      Public Postal As Integer

Das Problem wie vorher beschrieben, zeigt sich nun. Die doppelten Datensätze werden trotz LINQ distinct nicht gefiltert. Alle Daten sind in der Liste und damit die Länder mehrfach.

Abhilfe schafft die LINQ Grouping Funktion und die Auswahl mit First. First erwartet einen Lambda Ausdruck als Parameter.

   1:  From c In co
   2:  Group c By c.CountryID Into Group
   3:  Select New Adresse With {.CountryID = Group.First(Function(x) x.CountryID).CountryID,
   4:                            .Country = Group.First(Function(x) x.CountryID).Country
Kommentare sind geschlossen