web-dev-qa-db-ja.com

EF Coreは翻訳できなかったため、ローカルで評価されます

クライアント側で評価されるEF Core 1.1.2のクエリがあり、それをSQLに変換するより良い方法があるかどうか知りたいですか?

クエリ:

from l in _ctx.Locations
  join i in _ctx.Inventories on l.Id equals i.LocationId
  join it in _ctx.Items on i.ItemId equals it.Id
  where l.ProjectId == projectid
  group i by new {l.Id, l.LHA} into il
  select new InventoryLocations() {
      Id= il.Key.Id,
      LHA = il.Key.LHA,
      FlaggedItems = il.Any(x=>x.Item != null && x.Item.Flagged)
  }

そうでない場合、他にどのようなオプションがありますか?

  • 私が知っているように、ビューをマッピングする方法はまだありません。
  • FromSQL()メソッドはコンテキストで既知の型のみを返すことができ、たとえば、1つのモデルを[NotMapped]としてマークすることはできません。
  • .netコアがターゲットフレームワークであるため、ef6に戻すことはできません。

モデル:

public class Location
{
    public Guid Id { get; set; }

    [ForeignKey("Project")]
    public Guid ProjectId { get; set; }
    public Project Project {get; set; }
    public string Name { get; set; }
    public string LHA { get; set; }

    [ForeignKey("ScanUser")]
    public Guid? ScanUserId { get; set; }
    public User ScanUser { get; set; }
    [ForeignKey("CheckUser")]
    public Guid? CheckUserId { get; set; }
    public User CheckUser { get; set; }

    [ForeignKey("GroupLeader")]
    public Guid? GroupLeaderId { get; set; }
    public User GroupLeader { get; set; }
    public int State { get; set; }
}

public class Inventory
{
    public Guid Id { get; set; }

    [ForeignKey("Project")]
    public Guid ProjectId { get; set; }
    public Project Project {get; set; }
    public string EANCode { get; set; }
    [ForeignKey("Location")]
    public Guid LocationId { get; set; }
    public Location Location { get; set; }
    public Double ScanQty { get; set; }
    [ForeignKey("ScanUser")]
    public Guid? ScanUserId { get; set; }
    public User ScanUser { get; set; }
    public DateTime? ScanDate { get; set; }
    [ForeignKey("Item")]
    public Guid? ItemId { get; set; }
    public Item Item { get; set; }

    [ForeignKey("InventoryTask")]
    public Guid? InventoryTaskId { get; set; }
    public InventoryTask InventoryTask { get; set; }

    [ForeignKey("CheckUser")]
    public Guid? CheckUserId { get; set; }
    public User CheckUser { get; set; }
    public DateTime? CheckDate { get; set; }
    public Double PrevQty { get; set; }
}

public class Item
{
    public Guid Id { get; set; }
    [ForeignKey("Project")]
    public Guid ProjectId { get; set; }
    public Project Project {get; set; }
    public string ItemNo { get; set; }
    public string EANCode { get; set; }
    public string Name { get; set; }
    public Double Price { get; set; }
    public bool Deleted { get; set; }
    public DateTime ChangeTime { get; set; }

    public Double BaseQty { get; set; }
    public bool Flagged { get; set; }
}
4
Perrier

現在(また、着信EF Core v.2.0のように見えます)、GroupByクエリはローカルで処理されるため、キーは可能な限り回避することです。

そして、あなたのクエリはそれに対して適格であるようです-最初にデータセットを結合で乗算し、次にそれをグループ化する必要はありません。

エンティティでreferenceナビゲーションプロパティとFKのみを使用していることに気づきました。基本的にはデータベーステーブルレコードやSQLのようです。しかしEFでは、対応するcollectionナビゲーションプロパティも定義できるため、論理ルートからクエリを開始できるため、結合やグループ化の必要がなくなります。

LocationからInventoryまでのナビゲーションプロパティを定義する場合

public class Location
{
    // ...
    public ICollection<Inventory> Inventories { get; set; }
}

その場合、同等のクエリは次のようになります。

from loc in _ctx.Locations
where loc.ProjectId == projectid
select new InventoryLocations()
{
    Id = loc.Id,
    LHA = loc.LHA,
    FlaggedItems = loc.Inventories.Any(inv => inv.Item != null && inv.Item.Flagged)
}

これは完全にSQLに変換されます。

なんらかの理由で上記のコレクションナビゲーションプロパティを作成できない場合でも、場所から開始して、手動でそれらをインベントリと関連付けることができます。

from loc in _ctx.Locations
where loc.ProjectId == projectid
select new InventoryLocations()
{
    Id = loc.Id,
    LHA = loc.LHA,
    FlaggedItems = _ctx.Inventories.Any(inv => loc.Id == inv.LocationId && inv.Item != null && inv.Item.Flagged)
}
4
Ivan Stoev

Ivanが正しく提案するようにナビゲーションプロパティを追加すると、次のようになります。

public class Location
{
    // ...
    public ICollection<Inventory> Inventories { get; set; }
}

次に、次のようなクエリを作成します。

var locations = _ctx.Locations
   .Include(x => x.Inventories)
       .ThenInclude(x => x.Item)
   .Where(x => x.ProjectId == projectId)
   .Select(loc => new InventoryLocations
   {
        Id = loc.Id,
        LHA = loc.LHA,
        FlaggedItems = loc.Inventories.Any(inv => inv.LocationId == loc.Id && inv.Item?.Flagged)
   });
0
Brad