Filtern in Joining-View (verknüpfte Tabellen)

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von zaphod.

    Filtern in Joining-View (verknüpfte Tabellen)

    Hallo Leute, hab hier schon viel hilfreiches gefunden, aber jetzt stecke ich fest. Hoffe, Ihr könnt helfen:

    Ich schreibe ein kleines Zeiterfassungsprogramm in VB.NET, das Daten in einer Access-Datenbank speichert. Diese enthält zwei Tabellen "Akten" und "Zeiten". In Zeiten werden die erfassten Arbeitszeiten gespeichert. Jeder Datensatz ist über das Feld "ID" mit dem Primärschlüssel "ID" der Tabelle Akten verknüpft. Dadurch werden die Zeiten bestimmten Akten zugeordnet. Das funktioniert alles.

    Ich lasse mir die Zeiten über ein DataGridView mit BindingSource als Datenquelle anzeigen. Über eine Textbox will ich die Zeiten nach zugehöriger Akte filtern. Das klappt einwandfrei über

    VB.NET-Quellcode

    1. ZeitenBindingSource.Filter = "ID = '" & Suche & "'"


    So kann der User aber nur nach der ID (Primärschlüssel) suchen. Jede Akte hat auch einen Namen, den ich nun zum Filtern nutzen möchte. Mit ZeitenBindingSource.Filter kann ich das nicht tun, weil der Name nicht in der Tabelle Zeiten gespeichert ist. Hier steht nur die ID der Akte drin.

    Ich habe verschiedenes probiert:

    1) Ich habe eine Abfrage in Access definiert, die Zeiten und Akten kombiniert, und habe diese als Datasource im DGV verwendet. Filtern nach Aktenname klappt dann einwandfrei. Aber ich weiß nicht wie ich im DGV vorgenommene Änderungen speichern kann. Der TableAdapterManager akzeptiert die Abfrage nicht und sagt, er habe keine Tabelle zum Speichern. Wahrscheinlich geht das Speichern bei einer Abfrage gar nicht (oder doch?). Dann scheidet diese Variante aus.

    2) Dann hab ich nach der äußerst hilfreichen :thumbup: Anleitung von ErfinderDesRades eine Joining-View erstellt, indem ich im DGV über eine DataGridViewCombobox den jeweiligen Inhalt von Akten.Name zu Zeiten.ID anzeigen lasse. Klappt als solches hervorragend, aber ich kann nicht filtern, weil die Spalte ja nur im DGV angezeigt wird, in der ZeitenBindingSource aber nicht vorhanden ist.

    Es sollte ja eigentlich keine so unübliche Sache sein, dass man in einer verknüpften Tabelle "mitsuchen" will. Ich bräuchte einen Filter, der ungefähr so lautet:

    Filter = Zeiten.ID = Suche OR (Zeiten.ID = Akten.ID AND Akten.Name LIKE *Suche*)

    Wie kann ich das so hinbekommen, dass ich das Ergebnis im DGV bearbeiten und speichern kann? ?(
    Definier nochmal deine gewünschte suche genauer. Das hier

    zaphod schrieb:

    Filter = Zeiten.ID = Suche OR (Zeiten.ID = Akten.ID AND Akten.Name LIKE *Suche*)
    scheint mir ganz unbrauchbar für garnix.

    Willst du alle Zeiten einer Akte finden, oder alle Zeiten aller Akten, deren Name meinetwegen mit A anfängt?
    Hallo ErfinderDesRades, ich will alle Zeiten aller Akten, deren Name den Suchtext enthält. Beispiel:

    Zeiten:
    ID der AkteStundenzahl
    12
    25

    Akten:
    IDName
    1Herbert Müller
    2Müllentsorgungs GmbH

    Sucheingabe des Users:
    "Müll" >> in beiden Akten enthalten, beide Zeiten sollen angezeigt werden
    "Schmidt" >> in Akten.Name nirgends enthalten, keine Zeiten anzeigen
    "Her" >> in Akte mit ID 1 enthalten, also nur Zeiteintrag mit Akten-ID = 1 anzeigen (2 Stunden)
    Nein, das war nur ein vereinfachtes Beispiel. Zu einer Akte mag es 1 Zeit geben, zu einer anderen 500. Das Prinzip ist wie bei einer Lieferanten/Artikel-Datenbank. Ein Lieferant kann nur einen Artikel haben oder viele.

    Ich habe mir überlegt, dass man ja erstmal Akte nach Name filtern könnte, im Hintergrund, vllt auch in einem extra DGV. Könnte man dann in einem zweiten Schritt prüfen, ob die Akten-ID des Zeiteintrags im Ergebnis der ersten Abfrage enthalten ist? Ich hab k.A. ob das geht und wie ich das in Code umsetzen könnte - hab wenig Ahnung von Datenbanken. Ich weiß vor allem nicht, wie ich das in den Filter-String reinbekommen könnte. Hast Du eine Idee?

    Wenn z.B. das hier

    VB.NET-Quellcode

    1. AktenDGV.DataSource = AktenBindingSource
    2. AktenBindingSource.Filter = "Name LIKE '*" & Suche & "*'"


    zwei Zeilen im AktenDGV ergibt, die zwei Akten repräsentieren mit sagen wir mal ID = 5 und ID = 10, wie kann ich dann die Zeiten selektieren, denen diese IDs zugewiesen sind?

    VB.NET-Quellcode

    1. ZeitenDGV.DataSource = ZeitenBindingSource
    2. ZeitenBindingSource.Filter = "ID ... " ??? in AktenDGV enthalten ???
    Hab grad ein Experiment gemacht, mit diesem Filter für eine ArticleBindingSource (die Artikel verweisen per CategoryID auf jeweils eine CategoryRow): CategoryID in (1,2)
    Macht sich ganz gut.
    Also du müsstest in 2 Schritten vorgehen:
    1. anhand der Textbox die entsprechenden AkteRows selektieren, und von denen die ID.
      Das machste besser mit Linq oder mit ner Schleife, dazu brauchste keine BindingSource
    2. die gefundenen IDs wie gezeigt in einen geeigneten Filterstring einbasteln.
      Mehr kann ich bislang nicht vorsagen, ich weiß ja nicht dein Datenmodell.

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

    Vielen Dank Erfinder. Ich hab mich an diesem Post orientiert und baue den Filter wie folgt auf:

    VB.NET-Quellcode

    1. Public Function NameFilter(ByRef AktenDataTable As DataTable, Suchtext As String) As String
    2. Dim F As String = ""
    3. For Each Row As DataRow In AktenDataTable.Select("Name LIKE '*" & Suchtext & "*'")
    4. If F = "" Then
    5. F = CStr(Row("ID"))
    6. Else
    7. F += ", " & CStr(Row("ID"))
    8. End If
    9. Next
    10. Return "ID IN (" & F & ")"
    11. End Function


    Das funktioniert jetzt erstmal. Ich fülle mit dem Filterstring BindingSource.Filter.

    Du schreibst, man brauche keine BindingSource, Linq wäre besser. Kannst Du das ein bisschen näher erläutern? Wie würde die Linq-Lösung ohne BindingSource aussehen? Wie anfangs schon gesagt, ich arbeite mit einer Mdb-Datenbank und will die Anzeige in einem DataGridView filtern.
    DataTable.Select() ist grausig, weil führt direkt in untypisierte Programmierung.

    Try this:

    VB.NET-Quellcode

    1. Public Function NameFilter(tbAkten As AktenDataTable, Suchtext As String) As String
    2. Suchtext = String.Concat("*", Suchtext, "*")
    3. Dim ids = From rwAkt In tbAkten Where rwAkt.Name Like Suchtext Select rwAkt.ID
    4. Return String.Concat("ID IN (", String.Join(",", ids), ")")
    5. End Function
    Dazu musst du einen Import auf dein Dataset setzen, oder den AktenDataTable-Typ voll ausschreiben.
    Ist der Import gesetzt, und der Typ richtig addressiert, so sagt dir Intellisense die ganze Abfrage vor.
    Siehe Film#8 in vier Views-Videos