Join 操作(C#)

联接两个数据源就是将一个数据源中的对象与另一个数据源中具有相同公共属性的对象相关联。

当查询所面向的数据源相互之间具有无法直接领会的关系时,Join 就成为一项重要的运算。 在面向对象的编程中,这可能意味着在未建模对象之间进行关联,例如对单向关系进行反向推理。 下面是单向关系的一个示例:Customer 类有一个类型为 City 的属性,但 City 类没有作为 Customer 对象集合的属性。 如果你具有一个 City 对象列表,并且要查找每个城市中的所有客户,则可以使用联接运算完成此项查找。

LINQ 框架中提供的 join 方法包括 JoinGroupJoin。 这些方法执行同等联接,即根据 2 个数据源的键是否相等来匹配这 2 个数据源的联接。 (与此相较,Transact-SQL 支持除“等于”之外的联接运算符,例如“小于”运算符。)用关系数据库术语表达,就是说 Join 实现了内部联接,这种联接只返回那些在另一个数据集中具有匹配项的对象。 GroupJoin 方法在关系数据库术语中没有直接等效项,但实现了内部联接和左外部联接的超集。 左外部联接是指返回第一个(左侧)数据源的每个元素的联接,即使其他数据源中没有关联元素。

下图显示了一个概念性视图,其中包含两个集合以及这两个集合中的包含在内部联接或左外部联接中的元素。

显示内部/外部的两个重叠圆圈。

方法

方法名 描述 C# 查询表达式语法 详细信息
Join 根据键选择器函数 Join 两个序列并提取值对。 join … in … on … equals … Enumerable.Join

Queryable.Join
GroupJoin 根据键选择器函数 Join 两个序列,并对每个元素的结果匹配项进行分组。 join … in … on … equals … into … Enumerable.GroupJoin

Queryable.GroupJoin

查询表达式语法示例

Join

下面的示例使用 join … in … on … equals … 子句基于特定值联接两个序列:

class Product
{
    public string Name { get; set; }
    public int CategoryId { get; set; }
}

class Category
{
    public int Id { get; set; }
    public string CategoryName { get; set; }
}

public static void Example()
{
    List<Product> products = new List<Product>
    {
        new Product { Name = "Cola", CategoryId = 0 },
        new Product { Name = "Tea", CategoryId = 0 },
        new Product { Name = "Apple", CategoryId = 1 },
        new Product { Name = "Kiwi", CategoryId = 1 },
        new Product { Name = "Carrot", CategoryId = 2 },
    };

    List<Category> categories = new List<Category>
    {
        new Category { Id = 0, CategoryName = "Beverage" },
        new Category { Id = 1, CategoryName = "Fruit" },
        new Category { Id = 2, CategoryName = "Vegetable" }
    };

    // Join products and categories based on CategoryId
    var query = from product in products
                join category in categories on product.CategoryId equals category.Id
                select new { product.Name, category.CategoryName };

    foreach (var item in query)
    {
        Console.WriteLine($"{item.Name} - {item.CategoryName}");
    }

    // This code produces the following output:
    //
    // Cola - Beverage
    // Tea - Beverage
    // Apple - Fruit
    // Kiwi - Fruit
    // Carrot - Vegetable
}

GroupJoin

下面的示例使用 join … in … on … equals … into … 子句基于特定值联接两个序列,并对每个元素的结果匹配项进行分组:

class Product
{
    public string Name { get; set; }
    public int CategoryId { get; set; }
}

class Category
{
    public int Id { get; set; }
    public string CategoryName { get; set; }
}

public static void Example()
{
    List<Product> products = new List<Product>
    {
        new Product { Name = "Cola", CategoryId = 0 },
        new Product { Name = "Tea", CategoryId = 0 },
        new Product { Name = "Apple", CategoryId = 1 },
        new Product { Name = "Kiwi", CategoryId = 1 },
        new Product { Name = "Carrot", CategoryId = 2 },
    };

    List<Category> categories = new List<Category>
    {
        new Category { Id = 0, CategoryName = "Beverage" },
        new Category { Id = 1, CategoryName = "Fruit" },
        new Category { Id = 2, CategoryName = "Vegetable" }
    };

    // Join categories and product based on CategoryId and grouping result
    var productGroups = from category in categories
                        join product in products on category.Id equals product.CategoryId into productGroup
                        select productGroup;

    foreach (IEnumerable<Product> productGroup in productGroups)
    {
        Console.WriteLine("Group");
        foreach (Product product in productGroup)
        {
            Console.WriteLine($"{product.Name,8}");
        }
    }

    // This code produces the following output:
    //
    // Group
    //     Cola
    //      Tea
    // Group
    //    Apple
    //     Kiwi
    // Group
    //   Carrot
}

请参阅