【问题标题】:LINQ Multiple Nested Table Aggregate QueryLINQ 多嵌套表聚合查询
【发布时间】:2011-08-12 23:51:42
【问题描述】:

我有 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(一对多)

InstallLocation -> ShipSetPart(一对多)

CmQueueItem -> ShipSetPart(一对多,通过 INVENTORY_ITEM_ID)

我试图弄清楚如何编写一个 LINQ 查询,我可以在其中创建一个匿名对象,其中包括每个 CmQueueItem 的 ShipSet 计数。

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

【问题讨论】:

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


    【解决方案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()
                     };
    

    【讨论】:

    • 这创建了以下 SQL,它看起来不像与 CmQueueItem 表挂钩:SELECT 1 AS C1, "Project2".INVENTORY_ITEM_ID AS INVENTORY_ITEM_ID, "Project2".C1 AS C2 FROM (SELECT "Distinct1".INVENTORY_ITEM_ID AS INVENTORY_ITEM_ID, (SELECT Count(1) AS A1 FROM SHIPSET_PART "Extent2" WHERE "Distinct1".INVENTORY_ITEM_ID = "Extent2".INVENTORY_ITEM_ID) AS C1 FROM (SELECT DISTINCT "Extent1".INVENTORY_ITEM_ID AS INVENTORY_ITEM Extent1" ) "Distinct1" ) "Project2"
    • EF 可能已经对其进行了优化,因为它发现它不需要在查询中包含该表。查看执行计划并将其与您的原始 SQL 进行比较,看看查询成本有何不同。您可能会发现这是一种改进。
    • 问题是我希望生成的查询仅检索 CmQueueItem 表中存在 inventory_item_id 的记录。存在的查询检索数万行,而它应该只返回数十行。所以基本上我想弄清楚如何使用 CmQueueDetail 表进行内部连接。有什么想法吗?
    • 完美!这正是我所希望的。关于 LINQ,我需要学习很多东西。 “让”是另一个。感谢您对此的帮助。如果我有代表,我会投票赞成。
    • 太棒了!我很高兴能帮上忙 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-12
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 2010-10-17
    相关资源
    最近更新 更多