从Entity Framework Core中的实体获取DbContext

4
有没有一种方法可以获取实体正在被跟踪的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 Core中获得这个结果?
3个回答

2

目前,EF Core还没有懒加载功能。如果有的话,那么从中生成的代理最终会引用加载它的DbContext。但是目前还没有这样的引用。


1

可以在实例/实体创建时使用依赖注入。以便稍后从实体中检索所属的dbcontext。

例如

class Book
{
  public readonly DBContext _dbcontext;

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

}

0

没有好的方法来做这件事。似乎在实体对象构造之后,在调用代码中枚举之前,没有简单的方法来注入任何代码。

子类化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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接