分组和左加入linq
Group by and left join in linq
有两个表,一个是 customers 有字段 customerID
,GroupID
另一个是 CustomerGroup
有字段 GroupID
,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
通常,如果您发现自己在执行左外联接后跟 GroupBy,那是因为您想要 "items with their sub-items"、喜欢 "Schools with their Students"、"Clients with their Orders"、"CustomerGroups with their Customers"等。如果需要,请考虑使用 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。从每个剩余的 CustomerGroup 中,通过将 CustomerGroup.GroupId 与每个 Customer.GroupId.
进行比较,获取其所有客户
结果是一系列 CustomerGroups,每个都有其客户。从此结果(参数 ResultSelector)中获取来自客户的 GroupName 和来自该组中客户的数量。
您的陈述是:
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"。最有效的方法是 select 仅 select 您实际计划使用的属性:
// 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
});
不select客户外键的原因是效率。如果 CustomerGroup [14] 有 1000 个客户,则该组中的每个客户的 GroupId 值都等于 [14]。这个值[14]发送1001次就浪费了。
有两个表,一个是 customers 有字段 customerID
,GroupID
另一个是 CustomerGroup
有字段 GroupID
,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
通常,如果您发现自己在执行左外联接后跟 GroupBy,那是因为您想要 "items with their sub-items"、喜欢 "Schools with their Students"、"Clients with their Orders"、"CustomerGroups with their Customers"等。如果需要,请考虑使用 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。从每个剩余的 CustomerGroup 中,通过将 CustomerGroup.GroupId 与每个 Customer.GroupId.
进行比较,获取其所有客户结果是一系列 CustomerGroups,每个都有其客户。从此结果(参数 ResultSelector)中获取来自客户的 GroupName 和来自该组中客户的数量。
您的陈述是:
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"。最有效的方法是 select 仅 select 您实际计划使用的属性:
// 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
});
不select客户外键的原因是效率。如果 CustomerGroup [14] 有 1000 个客户,则该组中的每个客户的 GroupId 值都等于 [14]。这个值[14]发送1001次就浪费了。