如何:使用联接将数据与 LINQ 合并(Visual Basic)

Visual Basic 提供了 JoinGroup Join 查询子句,使你能够基于集合之间的共同值合并多个集合的内容。 这些值称为 值。 熟悉关系数据库概念的开发人员会将 Join 子句识别为内部联接,而 Group Join 子句实际上是左外部联接。

本主题中的示例演示了使用JoinGroup Join查询子句来合并数据的几种方法。

创建项目并添加示例数据

创建包含示例数据和类型的项目

  1. 若要运行本主题中的示例,请打开 Visual Studio 并添加新的 Visual Basic 控制台应用程序项目。 双击 Visual Basic 创建的Module1.vb文件。

  2. 本主题中的示例使用 PersonPet 类型及来自以下代码示例的数据。 将此代码复制到 Visual Basic 创建的默认 Module1 模块中。

    Private _people As List(Of Person)
    Private _pets As List(Of Pet)
    
    Function GetPeople() As List(Of Person)
        If _people Is Nothing Then CreateLists()
        Return _people
    End Function
    
    Function GetPets(ByVal people As List(Of Person)) As List(Of Pet)
        If _pets Is Nothing Then CreateLists()
        Return _pets
    End Function
    
    Private Sub CreateLists()
        Dim pers As Person
    
        _people = New List(Of Person)
        _pets = New List(Of Pet)
    
        pers = New Person With {.FirstName = "Magnus", .LastName = "Hedlund"}
        _people.Add(pers)
        _pets.Add(New Pet With {.Name = "Daisy", .Owner = pers})
    
        pers = New Person With {.FirstName = "Terry", .LastName = "Adams"}
        _people.Add(pers)
        _pets.Add(New Pet With {.Name = "Barley", .Owner = pers})
        _pets.Add(New Pet With {.Name = "Boots", .Owner = pers})
        _pets.Add(New Pet With {.Name = "Blue Moon", .Owner = pers})
    
        pers = New Person With {.FirstName = "Charlotte", .LastName = "Weiss"}
        _people.Add(pers)
        _pets.Add(New Pet With {.Name = "Whiskers", .Owner = pers})
    
        ' Add a person with no pets for the sake of Join examples.
        _people.Add(New Person With {.FirstName = "Arlene", .LastName = "Huff"})
    
        pers = New Person With {.FirstName = "Don", .LastName = "Hall"}
        ' Do not add person to people list for the sake of Join examples.
        _pets.Add(New Pet With {.Name = "Spot", .Owner = pers})
    
        ' Add a pet with no owner for the sake of Join examples.
        _pets.Add(New Pet With {.Name = "Unknown",
                                .Owner = New Person With {.FirstName = String.Empty,
                                                          .LastName = String.Empty}})
    End Sub
    
    Class Person
        Public Property FirstName As String
        Public Property LastName As String
    End Class
    
    Class Pet
        Public Property Name As String
        Public Property Owner As Person
    End Class
    

使用 Join 子句执行内部联接

INNER JOIN 合并了两个集合中的数据。 指定键值相匹配的项包含在内。 在任一集合中,没有在另一个集合中找到匹配项的任何项都将被排除。

在 Visual Basic 中,LINQ 提供了两个选项用于执行 INNER JOIN:隐式联接和显式联接。

隐式联接指定要在子句中 From 联接的集合,并标识子句中的 Where 匹配键字段。 Visual Basic 根据指定的键字段隐式联接这两个集合。

当想要具体说明要在联接中使用的键字段时,可以使用子句来指定显式联接 Join 。 在这种情况下, Where 子句仍可用于筛选查询结果。

使用 Join 子句执行内部联接

  1. 将以下代码添加到 Module1 项目中的模块,以查看隐式和显式内部联接的示例。

    Sub InnerJoinExample()
        ' Create two lists.
        Dim people = GetPeople()
        Dim pets = GetPets(people)
    
        ' Implicit Join.
        Dim petOwners = From pers In people, pet In pets
                        Where pet.Owner Is pers
                        Select pers.FirstName, PetName = pet.Name
    
        ' Display grouped results.
        Dim output As New System.Text.StringBuilder
        For Each pers In petOwners
            output.AppendFormat(
              pers.FirstName & ":" & vbTab & pers.PetName & vbCrLf)
        Next
    
        Console.WriteLine(output)
    
        ' Explicit Join.
        Dim petOwnersJoin = From pers In people
                            Join pet In pets
                            On pet.Owner Equals pers
                            Select pers.FirstName, PetName = pet.Name
    
        ' Display grouped results.
        output = New System.Text.StringBuilder()
        For Each pers In petOwnersJoin
            output.AppendFormat(
              pers.FirstName & ":" & vbTab & pers.PetName & vbCrLf)
        Next
    
        Console.WriteLine(output)
    
        ' Both queries produce the following output:
        '
        ' Magnus:    Daisy
        ' Terry:     Barley
        ' Terry:     Boots
        ' Terry:     Blue Moon
        ' Charlotte: Whiskers
    End Sub
    

使用 Group Join 子句执行左外部联接

左外部联接包含联接左侧集合中的所有项,并仅包含联接右侧集合中的匹配值。 联接的右侧集合中不存在左侧集合中的匹配项的任何项都将从查询结果中排除。

Group Join 子句实际上会执行左外部联接。 通常所谓的左外部联接和 Group Join 子句返回的内容之间的区别在于,Group Join 子句组来自联接的右侧集合(对应于左侧集合中每个项)。 在关系数据库中,LEFT OUTER JOIN 返回未分组的结果,其中查询结果中的每个项都包含联接中两个集合中的匹配项。 在这种情况下,对于来自右侧集合的每个匹配项,都会重复联接左侧集合中的项。 完成下一步后,你将看到这是什么样子。

可以通过扩展查询为每个分组查询结果返回一个项,将 Group Join 查询的结果作为未分组结果检索。 为此,必须确保对分组集合的 DefaultIfEmpty 方法进行查询。 这可确保联接的左侧集合中的项仍包含在查询结果中,即使它们没有来自右侧集合的匹配结果。 如果联接的右侧集合中没有匹配值,则可以向查询添加代码以提供默认结果值。

使用 Group Join 子句执行左外部联接

  1. 将以下代码添加到项目中的 Module1 模块,以查看分组左外部联接和未组合的左外部联接的示例。

    Sub LeftOuterJoinExample()
        ' Create two lists.
        Dim people = GetPeople()
        Dim pets = GetPets(people)
    
        ' Grouped results.
        Dim petOwnersGrouped = From pers In people
                               Group Join pet In pets
                                 On pers Equals pet.Owner
                               Into PetList = Group
                               Select pers.FirstName, pers.LastName,
                                      PetList
    
        ' Display grouped results.
        Dim output As New System.Text.StringBuilder
        For Each pers In petOwnersGrouped
            output.AppendFormat(pers.FirstName & ":" & vbCrLf)
            For Each pt In pers.PetList
                output.AppendFormat(vbTab & pt.Name & vbCrLf)
            Next
        Next
    
        Console.WriteLine(output)
        ' This code produces the following output:
        '
        ' Magnus:
        '     Daisy
        ' Terry:
        '     Barley
        '     Boots
        '     Blue Moon
        ' Charlotte:
        '     Whiskers
        ' Arlene:
    
        ' "Flat" results.
        Dim petOwners = From pers In people
                        Group Join pet In pets On pers Equals pet.Owner
                        Into PetList = Group
                        From pet In PetList.DefaultIfEmpty()
                        Select pers.FirstName, pers.LastName,
                               PetName =
                                 If(pet Is Nothing, String.Empty, pet.Name)
    
    
        ' Display "flat" results.
        output = New System.Text.StringBuilder()
        For Each pers In petOwners
            output.AppendFormat(
              pers.FirstName & ":" & vbTab & pers.PetName & vbCrLf)
        Next
    
        Console.WriteLine(output.ToString())
        ' This code produces the following output:
        '
        ' Magnus:	    Daisy
        ' Terry:	    Barley
        ' Terry:	    Boots
        ' Terry:	    Blue Moon
        ' Charlotte:	Whiskers
        ' Arlene:	  
    End Sub
    

使用复合键执行联接

可以使用And关键字在JoinGroup Join子句中标识用于匹配联接集合中的值的多个键字段。 关键字 And 指定所有指定的键字段必须与要联接的项匹配。

使用组合键执行联接

  1. 将以下代码添加到 Module1 项目中的模块,以查看使用组合键的联接示例。

    Sub CompositeKeyJoinExample()
        ' Create two lists.
        Dim people = GetPeople()
        Dim pets = GetPets(people)
    
        ' Implicit Join.
        Dim petOwners = From pers In people
                        Join pet In pets On
                          pet.Owner.FirstName Equals pers.FirstName And
                          pet.Owner.LastName Equals pers.LastName
                        Select pers.FirstName, PetName = pet.Name
    
        ' Display grouped results.
        Dim output As New System.Text.StringBuilder
        For Each pers In petOwners
            output.AppendFormat(
              pers.FirstName & ":" & vbTab & pers.PetName & vbCrLf)
        Next
    
        Console.WriteLine(output)
        ' This code produces the following output:
        '
        ' Magnus:    Daisy
        ' Terry:     Barley
        ' Terry:     Boots
        ' Terry:     Blue Moon
        ' Charlotte: Whiskers
    End Sub
    

运行代码

添加代码以运行示例

  1. Sub Main 项目中的 Module1 模块替换为以下代码,以运行本主题中的示例。

    Sub Main()
        InnerJoinExample()
        LeftOuterJoinExample()
        CompositeKeyJoinExample()
    
        Console.ReadLine()
    End Sub
    
  2. 按 F5 运行示例。

另请参阅