LINQ Abfrage wie in SQL 'in'

  • VB.NET

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von VB1963.

    LINQ Abfrage wie in SQL 'in'

    yo Leute,

    mir fällt leider kein besserer Titel ein. Deswegen schildere ich mal mein Vorhaben.
    Ich habe eine List(of T) wo ich generell mal alle Items reinlade.
    Nun möchte ich aber, dass für eine Combobox DataSource nicht alle angezeigt werden. Ist ja nicht so schwer:

    VB.NET-Quellcode

    1. ComboBox1.DataSource = LISTE.FindAll(Function(n) n.Status = Status.Aktiv)

    Klar ersichtlich: Es sollen nur aktive Einträge hier eingetragen werden.
    Zusätzlich will ich aber auch bestimmte inaktive Einträge anzeigen deren Anzahl ich vorher nicht weiß, diese jedoch in einer anderen Liste aufgelistet sind.

    VB.NET-Quellcode

    1. ComboBox1.DataSource = LISTE.FindAll(Function(n) n.Status = Status.Aktiv or n.ID in ANDERELISTE) ' funzt natürlich nicht. ANDERELISTE hat eine ID Property auf die ich abfragen will


    Wie schaff ich es, dass ich eben diese anderen Einträge zusätzlich mit aufnehme?

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Hey,

    wenn ich Dich richtig verstanden hab, sollte es in Etwa so gehen:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _list1 As New List(Of Test)
    3. Private _list2 As New List(Of Test)
    4. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    5. _list1.Add(New Test With {.CurrentStatus = Test.Status.Active, .TestString = "a"})
    6. _list1.Add(New Test With {.CurrentStatus = Test.Status.Inactive, .TestString = "b"})
    7. _list1.Add(New Test With {.CurrentStatus = Test.Status.Active, .TestString = "c"})
    8. _list1.Add(New Test With {.CurrentStatus = Test.Status.Active, .TestString = "d"})
    9. _list1.Add(New Test With {.CurrentStatus = Test.Status.Inactive, .TestString = "e"})
    10. _list2.Add(New Test With {.CurrentStatus = Test.Status.Active, .TestString = "a"})
    11. _list2.Add(New Test With {.CurrentStatus = Test.Status.Inactive, .TestString = "b"})
    12. _list2.Add(New Test With {.CurrentStatus = Test.Status.Inactive, .TestString = "c"})
    13. _list2.Add(New Test With {.CurrentStatus = Test.Status.Inactive, .TestString = "d"})
    14. _list2.Add(New Test With {.CurrentStatus = Test.Status.Inactive, .TestString = "e"})
    15. Dim result As IEnumerable(Of Test) = _list1.Where(Function(x) x.CurrentStatus = Test.Status.Active) _
    16. .Union(_list2.Where(Function(x) x.TestString = "e"))
    17. ListBox1.DataSource = result.ToList()
    18. ListBox1.DisplayMember = "TestString"
    19. End Sub
    20. End Class
    21. Public Class Test
    22. Public Property CurrentStatus As Status
    23. Public Property TestString As String
    24. Public Enum Status As Integer
    25. Active = 0
    26. Inactive = 1
    27. End Enum
    28. End Class
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Naja fast richtig verstanden :)
    Bei deinem Beispiel werden alle angezeigt welche Aktiv sind (wie bei mir) und zusätzlich alle bei denen die TestString Property "e" ist.
    Ich brauch alle die Aktiv sind und zusätzlich alle Einträge bei denen die ID mit den IDs der anderen Liste übereinstimmt.
    In SQL würde das so aussehen:

    SQL-Abfrage

    1. select * from LISTE where status = 'Aktiv' or ID in (select ID from andererliste)


    Um bei deinem Beispiel zu bleiben, bräuchte ich zB nicht nur alle "e" sondern auch noch "a" und "b"

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „fichz“ ()

    Da fällt mir dann nur mehr sowas ein:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _list1 As New List(Of Test)
    3. Private _list2 As New List(Of Test)
    4. Private _result As New List(Of Test)
    5. Private Sub frm_Shown(sender As System.Object, e As System.EventArgs) Handles MyBase.Shown
    6. _list1.Add(New Test With {.CurrentStatus = True, .ID = 1, .TestString = "a"})
    7. _list1.Add(New Test With {.CurrentStatus = False, .ID = 2, .TestString = "b"})
    8. _list1.Add(New Test With {.CurrentStatus = True, .ID = 3, .TestString = "c"})
    9. _list1.Add(New Test With {.CurrentStatus = True, .ID = 4, .TestString = "d"})
    10. _list1.Add(New Test With {.CurrentStatus = False, .ID = 5, .TestString = "e"})
    11. _list2.Add(New Test With {.CurrentStatus = True, .ID = 1, .TestString = "a1"})
    12. _list2.Add(New Test With {.CurrentStatus = True, .ID = 3, .TestString = "b3"})
    13. _list2.Add(New Test With {.CurrentStatus = False, .ID = 8, .TestString = "c"})
    14. _list2.Add(New Test With {.CurrentStatus = True, .ID = 7, .TestString = "d"})
    15. _list2.Add(New Test With {.CurrentStatus = False, .ID = 2, .TestString = "e2"})
    16. '
    17. _result.AddRange(From x In _list1 Where x.CurrentStatus)
    18. _result.AddRange(From x In _list1 Where x.CurrentStatus Join y In _list2 On x.ID Equals y.ID Select y)
    19. ListBox1.DataSource = _result.ToList
    20. ListBox1.DisplayMember = "TestString"
    21. End Sub
    22. End Class
    23. Public Class Test
    24. Public Property CurrentStatus As Boolean
    25. Public Property ID As Integer
    26. Public Property TestString As String
    27. End Class

    Die Ausgabeliste hintereinander mit den Abfragen auffüllen...
    @Artentus:
    Genau das ist es! Ein Problem entsteht mit dieser Abfrage aber wo ich nur einen "unschönen" Workaround finde.
    Da "ANDERELISTE" ja keine List(Of Integer) ist sondern auch eine List(Of Klasse) kann er natürlich nicht Klasse mit Integer vergleichen.
    Wie schaff ich es noch, dass ich direkt die Eigenschaft ID von "ANDERELISTE" mit n.ID vergleichen kann?

    Workaround:

    VB.NET-Quellcode

    1. Dim test As New List(Of Integer)
    2. For Each item In ANDERELISTE
    3. test.Add(item.ID)
    4. Next
    5. Dim tmp = LISTE.FindAll(Function(n) n.Status = Status.Aktiv OrElse test.Contains(n.ID)).ToList


    Den ForEach Part würd ich mir (wenn halt möglich) noch sparen :)

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    na, denn ist meine Lösung ja wieder im Geschäft :D

    Alternativ mit HashSet:

    VB.NET-Quellcode

    1. Dim hshs = New HashSet(Of Integer)(From x In _list2 Select x.ID)
    2. ListBox1.DataSource = _list1.Where(Function(x) x.CurrentStatus OrElse hshs.Contains(x.ID)).ToArray
    Das HashSet bildet genau den Sql-SubSelect nach.

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

    Gerade versucht und funktioniert wunderbar :)
    .Any gibt also bei allen Elementen True zurück, welches in der Liste zutrifft? Im Grunde genommen ist das ja genau DAS "SQL-In". Hoffe hab das so richtig verstanden.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    .Any gibt also bei allen Elementen True zurück, welches in der Liste zutrifft?

    Jein - .Any gibt kein Element einer Auflistung zurück. Stattdessen bestimmt sie, ob die Auflistung Elemente enthält oder Elemente eine Bedinung erfüllen. Das ist der Gegensatz von .All, da müssen alle Elemente eine Bedinung erfüllen...