2017-01-27 16 views
0

エンティティが(もしあれば)エンティティが追跡されているDbContextのインスタンスを取得する方法はありますか?Entity FrameworkコアのエンティティからDbContextを取得

私はEF6 Get DbContext from Entity in Entity Framework

public static DbContext GetDbContextFromEntity(object entity) 
{ 
    var object_context = GetObjectContextFromEntity(entity); 

    if (object_context == null) 
     return null; 

    return new DbContext(object_context, dbContextOwnsObjectContext: false); 
} 

private static ObjectContext GetObjectContextFromEntity(object entity) 
{ 
    var field = entity.GetType().GetField("_entityWrapper"); 

    if (field == null) 
     return null; 

    var wrapper = field.GetValue(entity); 
    var property = wrapper.GetType().GetProperty("Context"); 
    var context = (ObjectContext)property.GetValue(wrapper, null); 

    return context; 
} 

については、以下の提案/ソリューションは、EFコアでこの結果を取得する方法はあります発見されましたか?

答えて

1

いいえEFコアにはまだレイジーローディングがありません。それがあった場合、それから生成されたプロキシは最終的にそれをロードしたDbContextへの参照を持ちます。今のところ、そのような参照はありません。

+0

ありがとう - これは私の絶望的な検索を終わらせる – Kathleen

0

これを行うには良い方法はありません。エンティティオブジェクトが構築された後、呼び出し元コードで列挙される前に、コードをプロセスに注入する簡単な方法はないようです。

Subclassing InternalDbSetは私が考えたものですが、.FindメソッドとIQueryable実装(DbSetを使用する主な方法)への呼び出しを解決することはできません。

私が左に見ることができる唯一のオプションは、DbSetへのアクセスを全く許可しないことですが、.Owner(またはあなたがそれを呼びたいもの)プロパティを設定するアクセサ関数を持っています。これは面倒です。通常は、作成するすべてのクエリタイプに対して関数を記述しなければならず、呼び出し元はLINQを使用できなくなります。しかし、醜く見えますが、ほとんどの柔軟性を維持するためにジェネリックスやコールバックを使用できます。ここに私が思いついたのがあります。

複雑なシステムの移植とクリーンアップに取り組んでいますので、まだ実際にテストする立場にはいませんが、コンセプトは健全です。コードは、必要に応じてさらに調整を行う必要があります。これは、QueryEntitiesの代わりに列挙するためにEnumerateEntitiesを使用している限り、レコードを処理する前にテーブル全体をプルダウンするなどの罰則はありませんが、もう一度これについて実際のテストをまだしていません。

private void InitEntity(Entity entity) { 
     if (entity == null) { 
      return; 
     } 
     entity.Owner = this; 
     // Anything you want to happen goes here! 
    } 
    private DbSet<Entity> Entities { get; set; } 
    public IEnumerable<Entity> EnumerateEntities() { 
     foreach (Entity entity in this.Entities) { 
      this.InitEntity(entity); 
      yield return entity; 
     } 
    } 
    public IEnumerable<Entity> EnumerateEntities(Func<DbSet<Entity>, IEnumerable<Entity>> filter) { 
     IEnumerable<Entity> ret = filter(this.Entities); 
     foreach (Entity entity in ret) { 
      this.InitEntity(entity); 
      yield return entity; 
     } 
    } 
    public T QueryEntities<T>(Func<DbSet<Entity>, T> filter) { 
     if (filter is Func<DbSet<Entity>, Entity>) { 
      T ret = filter(this.Entities); 
      this.InitEntity(ret as Entity); 
      return ret; 
     } 

     if (filter is Func<DbSet<Entity>, IEnumerable<Entity>>) { 
      IEnumerable<Entity> ret = filter(this.Entities) as IEnumerable<Entity>; 
      // You should be using EnumerateEntities, this will prefetch all results!!! Can't be avoided, we can't mix yield and no yield in the same function. 
      return (T)ret.Select(x => { 
       this.InitEntity(x); 
       return x; 
      }); 
     } 

     return filter(this.Entities); 
    } 
    public void QueryEntities(Action<DbSet<Entity>> filter) => filter(this.Entities); 
関連する問題