LinqToDataset

    • VB.NET

    Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

      LinqToDataset

      Hier ein kleines Beispiel, wie man mit Linq eine typisierte DataTable abfragen kann, und die Abfrage in ein DataView verwandeln, welches man als DataSource eines DatagridViews verwenden kann.

      Das ist eine Filter-Technik, die mehr Möglichkeiten bietet als olle DataExpressions, und die Abfrage ist typisiert, während bei DataExpressions ja der Ausdruck in einem String notiert wird, wo der Compiler nicht reingucken kann, ob das funktioniert.

      Also hier ein Filter, der nach Artikelname und KategorieName filtert, mit der besonderheit, dass Kategoriename gar keine Spalte der ArtikelDataTable ist, sondern KategorieName ist eine Spalte der übergeordneten KategorieDataTable.
      (Datenmodell: Kategorien->Artikel)

      VB.NET-Quellcode

      1. Private Sub FilterButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btApply.Click, btRemove.Click
      2. Select Case True
      3. Case sender Is btApply
      4. Dim filtered = From rw In NorthWindDts.Artikel _
      5. Where rw.Artikelname Like ArtikelnameTextBox.Text & "*" AndAlso rw.KategorienRow.Kategoriename Like KategorienameTextBox.Text & "*"
      6. ArtikelDataGridView.DataSource = filtered.AsDataView
      7. Case sender Is btRemove
      8. ArtikelDataGridView.DataSource = ArtikelBindingSource
      9. End Select
      10. End Sub





      [Edit 2017-10]: Bitter-Wermuts-Tropfen
      Die hier gezeigte Linq2Dataset-Filter-Methode ist nicht kompatibel zur Filterung durch Setzen der BindingSource.Filter-Property.
      Hier ( <- folge dem Link ) hat @OliverSte sich damit herumgeärgert, und konnte schließlich den Fail genauer berschreiben:

      OliverSte schrieb:

      Der BS-Filter sucht nicht in der DataView, sondern in der alten DataSource. Wenn da was ist, wird es gezeigt und die LINQ-DataView verworfen.
      Ich vermute, das hat technische Gründe, zB könnte ich mir vorstellen, dass beim Setzen eines Bs-Filters ein neues DataView erzeugt wird, und als DataSource hergenommen.
      Wenn dem so ist, ist logisch, dass das vorherige Linq2Dts-Dataview verloren geht.
      Dateien

      Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Mit Linq2Dataset kann man ein Dataset zwar beliebig abfragen, aber die fabelhafte .AsDataView()-Extension ist nur für bestimmte Abfragen verfügbar, nämlich Abfragen auf genau eine DataTable, und nur die Where - Einschränkung.
      Hier wollte ich mal nur die neuesten Bestellungen aller Kunden er-filtern, und mußte ein nicht ganz hübsches Hilfskonstrukt konstruieren:

      VB.NET-Quellcode

      1. Private Sub ckBestellungFilter_CheckedChanged(sender As Object, e As EventArgs) Handles ckBestellungFilter.CheckedChanged
      2. If ckBestellungFilter.Checked Then
      3. Dim idSelector = From rw In NorthWindDts.Bestellungen Group By rw.KundeID Into newest = MaxBy(rw.Bestelldatum) Select ID = newest.bestellid
      4. Dim ids = New HashSet(Of Integer)(idSelector)
      5. Dim filter = From rw In NorthWindDts.Bestellungen Where ids.Contains(rw.BestellID)
      6. BestellungenDataGridView.DataSource = filter.AsDataView
      7. Else
      8. BestellungenDataGridView.DataSource = BestellungenBindingSource
      9. End If
      10. End Sub
      also der Selector gruppiert die Bestellungen nach KundeID und selectiert dann die BestellId der Bestellung mittm neuesten Bestelldatum.
      Diese Ids werden in ein Hashset gepackt, und dann kann der filter immer gugge, welche BestellRows in diesem Hashset aufgeführt sind.




      Hier noch eine verschärfte Formulierung desselben Vorgangs:

      VB.NET-Quellcode

      1. Private Sub ckBestellungFilter_CheckedChanged(sender As Object, e As EventArgs) Handles ckBestellungFilter.CheckedChanged
      2. If ckBestellungFilter.Checked Then
      3. Dim allOrders = NorthWindDts.Bestellungen
      4. Dim choosenOrders = New HashSet(Of BestellungenRow)(From rw In allOrders Group By rw.KundeID Into MaxBy(rw.Bestelldatum) Select MaxBy)
      5. BestellungenDataGridView.DataSource = allOrders.Where(AddressOf choosenOrders.Contains).AsDataView
      6. Else
      7. BestellungenDataGridView.DataSource = BestellungenBindingSource
      8. End If
      9. End Sub
      weil ebensogut, wie man die Ids der Bestellungen ins Hashset packen kann, kann man auch gleich die Bestellungen selbst reinpacken.
      Die MaxBy-Funktion habich übrigens selbst gebastelt, und bereits hier veröffentlicht.

      Aber sie liegt auch den Sources in post#1 bei

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Angehängtes Projekt zeigt einen m:n-View mit Artikeln und Kategorien: einem Artikel können mehrere Kategorien zugeordnet sein.
      Anforderung ist nun, einen Kategorien-Filter zu schaffen, der nur Kategorien anzeigt (rechts), die dem aktuell angewählten Artikel noch nicht zugeordnet sind:


      So ein Filter ist für Standard-Databinding auch bisserl zu kompliziert, daher verarbeite ich das Bindingsource_ListChanged-Event, was darauf reagiert, wenn die Zuordnungs-Ansicht in einer der folgenden Hinsichten geändert wird: Reset, Add or Delete

      VB.NET-Quellcode

      1. Private Sub bsArtikelKategorie_ListChanged(sender As Object, e As ListChangedEventArgs) Handles bsArtikelKategorie.ListChanged
      2. If e.ListChangedType > ListChangedType.ItemDeleted Then Return 'only observe ListChangedType.Reset (=0), .ItemAdded (=1), .ItemDeleted(=2)
      3. Dim artikelKats = bsArtikelKategorie.All(Of KategorieArtikelRow).Select(Function(artKat) artKat.KategorieRow) ' die dem Artikel zugeordneten Kategorien
      4. Dim hshArtikelKats = New HashSet(Of KategorieRow)(artikelKats)
      5. Dim dv = TryCast(dgvOtherKategorie.DataSource, DataView) : If dv.NotNull Then dv.Dispose() ' vorheriges Dataview ggfs. disposen
      6. dv = NorthWindDts.Kategorie.Where(Function(kat) Not hshArtikelKats.Contains(kat)).AsDataView ' LinqToDataset-DataView der dem Artikel nicht zugeordneten Kategorien
      7. dgvOtherKategorie.DataSource = dv
      8. End Sub
      Der Code tickt ähnlich dem des vorherigen Posts: Ein Hashset wird gebildet, dessen .Contains()-Aussage zum Bestandteil des mit Linq2Dataset gebildeten Filter-DataViews wird.
      Dateien

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()