EntityFramework Core:派生型のEager Loadingナビゲーションプロパティ

c# entity-framework entity-framework-core linq-to-sql

質問

私はEntityFramework Coreを使用しており、一部の派生型(すべて1つのクエリ内)にのみ存在するナビゲーションプロパティを熱心にロードしようとしています。たぶんシンプルな例でデモンストレーションするのが最も良いでしょう。

のようないくつかのデータ構造を持っていると仮定

class Transaction
{
    public Product product { get; set; }
    public DateTime date { get; set; }
}

abstract class Product
{
    public string Name { get; set; }
}

class PhysicalProduct : Product
{
    public Photo photo { get; set; }
}

class Service : Product
{
    public Person provider { get; set; }
}

そして、いくつかのDbContext

class MyContext : DbContext
{
    public DbSet<Transaction> Transactions;
}

MyContext.Transactionsをクエリして、すべてのトランザクションを返すようにするにはどうすればいいですか?(積極的な負荷)Transaction.product.photo(製品がPhysicalProductの場合)、Transaction.product.provider(製品がサービスの場合)前述のように、1つのクエリでこれを達成しようとします。

私は以下を試した:

// This is conceptually what I want to achieve.
// Not very surprisingly, this will throw an InvalidCastException
Transactions
  .Include(x => ((PhysicalProduct)x.product).photo)
  .Include(x => ((Service)x.product).provider)
  .ToList();

// Based on http://stackoverflow.com/questions/7635152/entity-framework-eager-loading-of-subclass-related-objects
// Projection into an anonymous type, then transform back.
// doesn't work though, throws an InvalidOperationException, e.g.
// The property "photo" on entity type "Product" could not be found. Ensure that the property exists and has been included in the model.
// i.e. even though I wrapped this in a condition (x.product is PhysicalProduct), seems like EntityFramework still tries to execute or parse the statement thereafter even if the condition is not true.
var query = Transactions.Select(x => new
{
  _transaction = x,
  _physicalProductPhoto = (x.product is PhysicalProduct) ? ((PhysicalProduct)x.product).photo : null;
  _serviceProvider = (x.product is Service) ? ((Service)x.product).provider : null;
})
.ToList()  // Execute query. Exception will be thrown at this step.
.Select(x =>
{
  var result = x._transaction;

  if (x.product is PhysicalProduct)
    ((PhysicalProduct)x.product).photo = x._physicalProductPhoto;
  else if(x.product is Service)
    ((Service)x.product).provider = x._serviceProvider;

  return result;
})
.ToList();

誰もこれを達成する方法を考えることができますか?ありがとう!

受け入れられた回答

昨日私はEF6 - EF Eagerで派生したクラスを取得するのと同様の問題と戦っていました 。現在、EFコアはその点では優れていません.3つのEF6の回避策では、ここで#2しか動作しないため、実際はそれが悪いです。

回避策は次のとおりです。

1つのクエリでは間違いなく実行できます。マスタークエリーを実行し、結果をメモリーに反映させる必要があります。次いで、導出された各ナビゲーションタイプに対して、PKを収集し、これらのキーによってフィルタリングされたクエリを実行する。最後に、EFナビゲーションプロパティフィックスアップのため、すべてのナビゲーションプロパティがロードされます。

var transactions = db.Transactions.Include(e => e.product).ToList();

var productIds = transactions.Where(e => e.product is PhysicalProduct)
    .Select(e => e.product.Id).Distinct();
db.BaseProducts.OfType<PhysicalProduct>().Include(e => e.photo)
    .Where(e => productIds.Contains(e.Id)).Load();

var serviceIds = transactions.Where(e => e.product is Service)
    .Select(e => e.product.Id).Distinct();
db.BaseProducts.OfType<Service>().Include(e => e.provider)
    .Where(e => serviceIds.Contains(e.Id)).Load();

人気のある回答

これはEFコアではまだサポートされていません。それを追跡する問題については、 https://github.com/aspnet/EntityFramework/issues/3910を参照してください

私は唯一の回避策は、複数のクエリを実行し、EFのコンテキストがあなたのためのフィックスアップを行うことだと思う。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ