LINQ多个嵌套表聚合查询
本文关键字:查询 嵌套 LINQ | 更新日期: 2023-09-27 18:05:33
我有4个实体,我已经定义了导航属性,如下所示:
internal class ShipSet
{
[Key]
[Column("SHIPSET_ID")]
public decimal ID { get; set; }
public virtual ICollection<InstallLocation> InstallLocations { get; set; }
}
internal class InstallLocation
{
[Key]
[Column("INSTLOC_ID")]
public decimal ID { get; set; }
[Column("SHIPSET_ID")]
public decimal ShipSetID { get; set; }
public virtual ICollection<ShipSetPart> ShipSetParts { get; set; }
public virtual ShipSet ShipSet { get; set; }
}
internal class ShipSetPart
{
[Key]
[Column("PARTS_ID")]
public decimal ID { get; set; }
[Column("INSTLOC_ID")]
public decimal InstallLocationID { get; set; }
public virtual CmQueueItem CmQueueItem { get; set; }
public virtual InstallLocation InstallLocation { get; set; }
}
internal class CmQueueItem
{
[Key]
[Column("INVENTORY_ITEM_ID")]
public decimal ID { get; set; }
public virtual ICollection<ShipSetPart> ShipSetParts { get; set; }
}
我有以下流畅的配置:
modelBuilder.Entity<CmQueueItem>().HasMany(p => p.ShipSetParts).
WithRequired(s=>s.CmQueueItem).Map(m=>m.MapKey("INVENTORY_ITEM_ID"));
modelBuilder.Entity<ShipSetPart>().HasRequired(p => p.InstallLocation);
modelBuilder.Entity<InstallLocation>().HasRequired(p => p.ShipSet);
modelBuilder.Entity<ShipSet>().HasRequired(p => p.Program);
modelBuilder.Entity<CmQueueItem>().Property(p => p.LastUpdateDate).IsConcurrencyToken();
简而言之,我有
ShipSet -> InstallLocation (1 to many)
InstallLocation -> ShipSetPart (1 to many)
CmQueueItem -> ShipSetPart (1 to many via INVENTORY_ITEM_ID)
我想弄清楚如何写一个LINQ查询,在那里我可以创建一个匿名对象,其中包括每个CmQueueItem的ShipSets计数。
var queueItems = from c in dbContext.CmQueueItems
select new
{
InventoryItemID = c.ID,
ShipSets = 0 //[magical LINQ goes here]
};
它应该生成一个类似于下面的SQL语句:
select d.inventory_item_id, count(a.shipset_id) as ShipSets
from shipsets a,
instlocs b,
ss_parts c,
cm_queue d
where a.shipset_id = b.shipset_id
and b.instloc_id = c.instloc_id
and c.inventory_item_id = d.inventory_item_id
group by d.inventory_item_id;
我是LINQ的新手,很难理解如何执行这样的聚合和分组。什么好主意吗?
下面提供的答案是在LINQ中使用"let"关键字:
var query = from c in dbContext.CmQueueItems
let shipSets = (from s in c.ShipSetParts
select s.InstallLocation.ShipSet)
select new
{
InventoryItemId = c.ID,
ShipSets = shipSets.Count(),
};
我还没有EF模型来测试这个,但是给这个试试…
UPDATE:下面是如何执行连接,看看它是否有效。有些地方不太对,因为我们不应该手动执行连接,这就是你的属性映射的作用。
var queueItems = from c in dbContext.CmQueueItems
join s in dbContext.ShipSetParts
on c.ID equals s.CmQueueItem.ID
group s by s.CmQueueItem.ID into grouped
select new
{
InventoryItemID = grouped.Key,
//this may need a distinct before the Count
ShipSets = grouped.Select(g => g.InstallLocation.ShipSetID).Count()
};
这里有一个更干净的替代方法,但我不确定它是否能在EF中工作。试一试,看看你觉得怎么样。
var queueItems = from c in dbContext.CmQueueItems
let shipSets = (from s in c.ShipSetParts
select s.InstallLocation.ShipSet)
select new
{
InventoryItemID = c.ID,
ShipSets = shipSets.Count()
};