2017-01-27 13 views
0

Есть ли способ получить экземпляр DbContext, который отслеживается сущностью (если есть)?Получить DbContext от Entity в Entity Framework Core

я нашел следующее предложение/решение для 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 Core еще не имеет ленивой загрузки. Если бы это было так, то прокси-сервер, сгенерированный из него, в конечном итоге имел бы ссылку на 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);