在SQL中,当您进行一系列连接时,它会将所有连接对象视为一个“超级对象”进行选择。只要您在分组中包含您选择的任何内容(除非它是由分组生成的,例如汇总一堆int列),当您按特定列分组时,情况仍然如此。
在LINQ中,您可以连续地执行一系列连接,并从中进行选择。但是,执行分组时,其行为会有所不同。查询样式LINQ中的语法只允许对单个表(即其中一个连接)进行分组,丢弃其他表。
对于一个示例,假设我们有几个表:
Request
-------
int ID (PK)
datetime Created
int StatusID (FK)
Item
----
int ID (PK)
string Name
RequestItem
-----------
int ID (PK)
int ItemID (FK)
int RequestID (FK)
int Quantity
Inventory
---------
int ID (PK)
int ItemID (FK)
int Quantity
LU_Status
---------
int ID (PK)
string Description
在我们的示例中,LU_Status在数据库中有三个值:
1 - New
2 - Approved
3 - Completed
这是实际情况的简化版本,引导我提出这个问题。给定此模式,需要生成一个报告,显示请求的项目数(状态不是“已完成”),已批准的项目(状态为“已批准”),分发的项目(状态为“已完成”)以及项目数库存(来自库存),全部按项目分组。如果这有点模糊,请看一下SQL或让我知道,我会尽量让它更清楚。
在SQL中我可能会这样做:
select i.Name,
Requested = sum(ri.Quantity),
Approved = sum(case when r.StatusID = 2 then ri.Quantity else 0 end)
Distributed = sum(case when r.StatusID = 3 then ri.Quantity else 0 end)
Storage = sum(Storage)
from RequestItem as ri
inner join Request as r on r.ID = ri.RequestID
inner join Item as i on i.ID = ri.ItemID
inner join (select ItemID, Storage = sum(Quantity)
from Inventory
group by ItemID)
as inv on inv.ItemID = ri.ItemID
group by i.Name
这会产生所需的结果。
我开始在LINQ中重写它,并且到目前为止:
var result = from ri in RequestItem
join r in Request on ri.RequestID equals r.ID
join i in Item on ri.ItemID equals i.ID
join x in (from inv in Inventory
group inv by inv.ItemID into g
select new { ItemID = g.Key, Storage = g.Sum(x => x.Quantity) })
on ri.ItemID equals x.ItemID
group...????
此时一切进展顺利,但我意识到我不能简单地按照i.Name分组,就像我在SQL中所做的那样。实际上,似乎没有办法将所有连接的东西组合在一起,以便我可以从中选择必要的东西,所以我被迫停在那里。我理解如何在更简单的情况下使用组语法(参见子查询),但如果有一种方法可以在LINQ中进行这种分组,我没有看到它,在这里和其他地方搜索并没有照亮我。
这是LINQ的缺点,还是我错过了什么?
答案 0 :(得分:3)
您可以在包含所需数据的分组中创建匿名类型:
var result = from ri in RequestItem
join r in Request on ri.RequestID equals r.ID
join i in Item on ri.ItemID equals i.ID
join x in (from inv in Inventory
group inv by inv.ItemID into g
select new { ItemID = g.Key, Storage = g.Sum(x => x.Quantity) })
on ri.ItemID equals x.ItemID
group new
{
i.Name,
r.StatusId,
ri.Quantity,
x.Storage,
}
by i.Name into grp
select new
{
grp.Key,
Requested = grp.Where(x => x.StatusID == 2).Sum(x => x.Quantity),
Distributed = grp.Where(x => x.StatusID == 3).Sum(x => x.Quantity),
Storage = grp.Sum(x => x.Storage)
}
(未经测试,显然,但它应该接近)。
答案 1 :(得分:2)
最简单的方法是使用group new { ... } by ...
构造,并在{ ... }
中包含稍后需要的联接中的所有项目,如下所示
var query =
from ri in db.RequestItem
join r in db.Request on ri.RequestID equals r.ID
join i in db.Item on ri.ItemID equals i.ID
join x in (from inv in db.Inventory
group inv by inv.ItemID into g
select new { ItemID = g.Key, Storage = g.Sum(x => x.Quantity) }
) on ri.ItemID equals x.ItemID
group new { ri, r, i, x } by i.Name into g
select new
{
Name = g.Key,
Requested = g.Sum(e => e.ri.Quantity),
Approved = g.Sum(e => e.r.StatusID == 2 ? e.ri.Quantity : 0),
Distributed = g.Sum(e => e.r.StatusID == 3 ? e.ri.Quantity : 0),
Storage = g.Sum(e => e.x.Storage)
};