【问题标题】:Group by and left join in linqGroup by 和 left 加入 linq
【发布时间】:2020-04-07 05:45:30
【问题描述】:

有两个表,一个是customers 有customerID,GroupID 字段,另一个是CustomerGroupGroupID,GroupName 字段,我想得到customerID 的数量在每个组中,这是 LINQ 语句:

var groups = from customerGroups in db.CustomerGroup 
                         join customers in db.Customers on customerGroups.GroupID equals customers.GroupID into gc
                         where customerGroups.MerchantID == merchantID
                         from subCustomerGroups in gc.DefaultIfEmpty()
                         group customerGroups by customerGroups.GroupName into grpCustomerGroups
                         select new { GroupName = grpCustomerGroups.Key, Quantity = customers.Count()};

问题是Quantity = customers.Count()无效,如何更正该语句? 预期的 sql 语句是

exec sp_executesql N'SELECT 
    1 AS [C1], 
    [GroupBy1].[K1] AS [GroupName], 
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT 
        [Extent1].[GroupName] AS [K1], 
        COUNT(CustomerID) AS [A1]
        FROM  [dbo].[CustomerGroup] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Customer] AS [Extent2] ON [Extent1].[GroupID] = [Extent2].[GroupID]
        WHERE [Extent1].[MerchantID] = @p__linq__0
        GROUP BY [Extent1].[GroupName]
    )  AS [GroupBy1]',N'@p__linq__0 bigint',@p__linq__0=9

【问题讨论】:

    标签: c# linq linq-to-sql


    【解决方案1】:

    通常,如果您发现自己在进行左外连接后跟 GroupBy,那是因为您想要“项目及其子项目”,例如“学校及其学生”、“客户及其订单”、“客户组”与他们的客户”等。如果需要,请考虑使用 GroupJoin 而不是“Join + DefaultIfEmpty + GroupBy”

    我对方法语法比较熟悉,所以我会使用那个。

    int merchantId = ...
    var result = dbContext.CustomerGroups
    
        // keep only the CustomerGroups from merchantId
        .Where(customerGroup => customerGroup.MerchantId == merchantId)
    
        .GroupJoin(dbContext.Customers,            // GroupJoin with Customers
        customerGroup => customerGroup.GroupId,    // from every CustomerGroup take the GroupId
        customer => customer.GroupId,              // from every Customer take the GroupId
    
        // ResultSelector:
        (customerGroup, customersInThisGroup) => new  // from every CustomerGroup with all its
        {                                             // matching customers make one new object
            GroupName = customerGroup.Key,
            Quantity = customersInThisGroup.CustomerId,  // ???
        });
    

    言辞:

    采用 CustomerGroups 的序列。仅保留属性 MerchantId 的值等于 MerchantId 的客户组。通过将 CustomerGroup.GroupId 与每个 Customer.GroupId 进行比较,从每个剩余的 CustomerGroup 中获取其所有客户。

    结果是一系列 CustomerGroup,每个都有自己的客户。从此结果(参数 ResultSelector)获取客户的 GroupName 和该组中客户的 Quantity。

    你的陈述是:

    Quantity = customers.CustomerID,
    

    这行不通。我确定这不是你想要的。唉,你忘了写你想要的。我认为是这样的:

    Quantity = customers.Count().
    

    但如果您想要此 CustomerGroup 中所有客户的 CustomerId:

    // ResultSelector:
    (customerGroup, customersInThisGroup) => new
    {                                           
        GroupName = customerGroup.Key,
        CustomerIds = customersInThisGroup.Select(customer => customer.CustomerId)
                                          .ToList(),
    );
    

    如果您愿意,您可以使用 ResultSelector 来获取“CustomerGroups with their Customers”。最有效的是只选择您实际计划使用的属性:

    // ResultSelector:
    (customerGroup, customersInThisGroup) => new
    {      
        // select only the CustomerGroup properties that you plan to use:
        Id = CustomerGroup.GroupId,
        Name = CustomerGroup.Name,
        ... // other properties that you plan to use
    
        Customers = customersInThisGroup.Select(customer => new
        {
             // again, select only the Customer properties that you plan to use
             Id = customer.Id,
             Name = customer.Name,
             ...
    
             // not needed, you know the value:
             // GroupId = customer.GroupId
        });
    

    不选择客户外键的原因是效率。如果 CustomerGroup [14] 有 1000 个客户,则该组中的每个客户的 GroupId 值都等于 [14]。发送此值 [14] 1001 次将是一种浪费。

    【讨论】:

    • 我根据您的回答做了一个小改动,它对我有用! (customerGroup, customersInThisGroup) => new // 从每个 CustomerGroup 及其所有匹配的客户中创建一个新对象 GroupID = customerGroup.GroupID, GroupName = customerGroup.GroupName, Quantity = customersInThisGroup.Count(), });跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多