2016-07-15 6 views
0

Я только начинаю с EF7 (CORE) и изо всех сил стараюсь найти правильную реализацию следующих. Скажем, у меня есть таблица с несколькими дочерними таблицами, которые, в свою очередь, имеют таблицы внуков (и в свою очередь они имеют таблицы внешнего ключа). Если бы я хотел доступ ко всему, что мне нужно что-то вроде этогоEntity Framework 7 несколько уровней дочерних таблиц

TABLE_A.Include(c => c.TABLE_B).ThenInclude(co => co.TABLE_C) 
           .ThenInclude(coi => coi.TABLE_D) 
           .ThenInclude(coia => coia.TABLE_E) 
     .Include(c => c.TABLE_B).ThenInclude(co => co.TABLE_F) 
           .ThenInclude(coa => coa.TABLE_G) 
           .ThenInclude(coaAcc => coaAcc.TABLE_H) 
           .ThenInclude(coaAccInt => coaAccInt.TABLE_D) 
           .ThenInclude(coaAccIntAgent => coaAccIntAgent.TABLE_E) 

Теперь я понимаю необходимость заковава включает включить все мои дочерние таблицы ... но я смотрю на SQL он выстреливает за кулисами и его отключение 11 SQL-операторов. Это кажется ужасно неэффективным.

Это лучший способ сделать это? Теперь у меня появилось новое требование добавить еще 3 дочерних таблицы в TABLE_B ... так что мне понадобится больше возможностей ... и, следовательно, больше вариантов будет выполняться за кулисами.

Я понимаю логику того, что я делаю ... и понимают, что в EF7 в настоящее время не поддерживается ленивая загрузка, но это не очень эффективный способ делать вещи, когда я могу написать хранимую процедуру, которая делает это за один раз.

Есть ли лучшие практики для таких вещей, как это или что-то, что я не понимаю, как использовать EF7, чтобы делать то, что мне нужно?

Любая помощь или руководство будут высоко оценены!

Благодаря

ответ

0

добавить этот метод расширения для вашего проекта, метод Load существует в эф 6.x, но не реализован еще в эф ядра:

public static void Load<TSource, TDestination>(this EntityEntry<TSource> entry, Expression<Func<TSource, IEnumerable<TDestination>>> path, Expression<Func<TDestination, TSource>> pathBack = null) where TSource : class where TDestination : class 
{ 
    var entity = entry.Entity; 
    var context = entry.Context; 
    var entityType = context.Model.FindEntityType(typeof(TSource)); 
    var keys = entityType.GetKeys(); 
    var keyValues = context.GetEntityKey(entity); 
    var query = context.Set<TDestination>() as IQueryable<TDestination>; 
    var parameter = Expression.Parameter(typeof(TDestination), "x"); 
    PropertyInfo foreignKeyProperty = null; 

    if (pathBack == null) 
    { 
     foreignKeyProperty = typeof(TDestination).GetProperties().Single(p => p.PropertyType == typeof(TSource)); 
    } 
    else 
    { 
     foreignKeyProperty = (pathBack.Body as MemberExpression).Member as PropertyInfo; 
    } 

    var i = 0; 

    foreach (var property in keys.SelectMany(x => x.Properties)) 
    { 
     var keyValue = keyValues[i]; 

     var expression = Expression.Lambda(
      Expression.Equal(
       Expression.Property(Expression.Property(parameter, foreignKeyProperty.Name), property.Name), 
       Expression.Constant(keyValue)), 
      parameter) as Expression<Func<TDestination, bool>>; 

     query = query.Where(expression); 

     i++; 
    } 

    var list = query.ToList(); 

    var prop = (path.Body as MemberExpression).Member as PropertyInfo; 
    prop.SetValue(entity, list); 
} 

public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class 
{ 
    var state = context.Entry(entity); 
    var metadata = state.Metadata; 
    var key = metadata.FindPrimaryKey(); 
    var props = key.Properties.ToArray(); 

    return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray(); 
} 

тогда, когда вам нужно каждый из навигационных свойств, Перед первым использованием вызова нагрузки (только один раз для любых навигационных свойств) метод как парованием:

//for first item 
var item = TABLE_A.First(); 
context.Entry(item).Load(b => b.TABLE_B); 

в зависимости от вашего случая использования, может включать или ThenInclude некоторые навигации в первом запросе, который загружает TABLE_A.

нагрузки метод расширения Source Link с большим количеством примеров

+0

Как это работает для коллекций? TABLE_A - это коллекция ... и каждый объект имеет список TABLE_B. Если я должен был использовать '_context.Entry (<Список таблицы А>) нагрузки (б => б .);.' я получаю ошибку 'IQueryable ' не содержит определение для «TABLE_B 'и никакой метод расширения' TABLE_B ', принимающий первый аргумент типа' IQueryable ', не может быть найден – rborob

+0

_context.Entry получить только один объект, вы загружаете сначала весь список TABLE_A и всякий раз, когда это необходимо для каждого элемента в списке TABLE_A, используйте этот код ex : var item = TABLE_A.First(); context.Entry (item) .Load (b => b.TABLE_B); <Фактически, на самом деле, похоже на LazyLoadining, но явная нагрузка навигации –

+0

Wow это ужасное решение. Если я отображу 300 элементов в представлении и покажу данные из 10 таблиц FK, я бы эффективно выполнил 3000 запросов за кулисами. – rborob

Смежные вопросы