繁体   English   中英

从 Entity Framework Core 中的实体获取 DbContext

[英]Get DbContext from Entity in Entity Framework Core

有没有办法获取正在跟踪实体的 DbContext 实例(如果有)?

在 Entity Framework 中EF6 Get DbContext from Entity找到了以下建议/解决方案

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 Core 中获得这个结果?

不可以。EF Core 还没有延迟加载。 如果有,那么,从它生成的代理最终将引用加载它的 DbContext。 到目前为止,还没有这样的参考。

没有好的方法可以做到这一点。 在构造实体对象之后但在调用代码中枚举它之前,似乎没有简单的方法可以将任何代码注入到流程中。

子类化 InternalDbSet 是我考虑过的事情,但您只能修复对 .Find 方法的调用,而 IQueryable 实现(您使用 DbSet 的主要方式)是遥不可及的。

所以我能看到的唯一选项是根本不允许访问 DbSet 但有访问器函数可以为我设置 .Owner (或任何你想调用的)属性。 这很麻烦,因为您通常必须为想要创建的每个查询类型编写一个函数,并且调用者不能再使用 LINQ。 但是我们可以使用泛型和回调来保留大部分灵活性,尽管它看起来很丑陋。 这是我想出的。

我正在移植和清理一个复杂的系统,所以我还不能真正测试这个,但这个概念是合理的。 代码可能需要进一步调整才能按需要工作。 只要您使用 EnumerateEntities 来枚举而不是 QueryEntities,这不应该有任何惩罚,例如在处理任何记录之前拉下整个表,但我还没有对此进行任何真正的测试。

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

可以在创建时对实例/实体使用依赖注入。 允许稍后从实体中检索拥有的 dbcontext。

例如

class Book
{
  public readonly DBContext _dbcontext;

  public Book(DBContext dbcontext)
  {
    _dbcontext = dbcontext;
  }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM