实体框架7多级子表

时间:2016-07-15 11:21:29

标签: entity-framework-core

我刚开始使用EF7(CORE),并且正在努力寻找以下的正确实现。假设我有一个包含多个子表的表,而子表又具有孙表(这些子表又具有外键表)。如果我想访问所有我需要的东西

 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语句。这看起来非常低效。

这是最好的方法吗?我现在已经收到了一个新的要求,要在TABLE_B中添加3个子表...所以我需要更多的包含..因此在幕后运行更多的选择。

我理解我正在做的事情背后的逻辑......并且理解EF7目前不支持延迟加载,但是当我编写存储过程时,这似乎不是一种非常有效的方法。它一气呵成。

对于像这样的事情或者我不了解如何使用EF7来做我需要的事情,是否有最佳实践?

非常感谢任何帮助或指导!

由于

1 个答案:

答案 0 :(得分:0)

将此扩展方法添加到您的项目中,Load方法存在于ef 6.x中,但尚未在ef核心中实现:

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

根据您的使用情况,可以在第一个加载TABLE_A的查询中包含或者包含一些导航。

加载扩展方法Source Link以及更多示例