LINQ-запрос с несколькими вложенными таблицами - PullRequest
1 голос
/ 13 августа 2011

У меня есть 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 до многих)

InstallLocation -> ShipSetPart (от 1 до многих)

CmQueueItem -> ShipSetPart (1 для многих через INVENTORY_ITEM_ID)

Я пытаюсь выяснить, как написать запрос LINQ, в котором я могу создать анонимный объект, который включает в себя количество ShipSets для каждого CmQueueItem.

            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 и с трудом понимаю, как выполнять агрегаты и группировки, подобные этой. Есть идеи?

Ответ, приведенный ниже, заключается в использовании ключевого слова let в LINQ:

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 Ответ

1 голос
/ 13 августа 2011

У меня нет модели 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()
                 };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...