Entity FrameworkコアのエンティティからDbContextを取得する

c# entity-framework entity-framework-core reflection

質問

エンティティが(もしあれば)DbContextのインスタンスを取得する方法はありますか?

私はEF6のための以下の提案/解決策を見つけましたEntity Frameworkのエンティティから DbContextを取得する

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コアでこの結果を得る方法はありますか?

受け入れられた回答

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


人気のある回答

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

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);


Related

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