2017-01-27 106 views
0

有沒有辦法獲得一個實體正在跟蹤(如果有的話)的DbContext實例?從實體框架核心中的實體獲取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。但我們可以使用泛型和回調來保留大部分的靈活性,儘管它看起來很醜。這是我想出來的。

我正在移植和清理一個複雜的系統,所以我不能真正測試這個,但這個概念是完善的。代碼可能需要進一步調整才能按需要工作。在處理任何記錄之前,只要您使用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);