LINQ多嵌套表聚合查询

时间:2011-08-12 23:51:43

标签: c# .net linq entity-framework linq-to-entities

我有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 - &gt; InstallLocation(1到多个)

InstallLocation - &gt; ShipSetPart(1到多个)

CmQueueItem - &gt; ShipSetPart(通过INVENTORY_ITEM_ID从1到多)

我正在试图弄清楚如何编写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(),
                            };

1 个答案:

答案 0 :(得分:1)

我还没有EF模型对此进行测试,但试一试......

更新:以下是执行连接的方法,看看是否有效。有些事情是不对的,因为我们不应该手动执行连接,这就是你的属性映射的用途。

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()
                 };