2016-07-15 87 views
0

我剛剛開始使用EF7(CORE),並且正在努力尋找以下的正確實現。假設我有一個包含多個子表的表,而這些子表又具有孫表(並且這些表又具有外鍵表)。如果我想獲得的一切我需要這樣的實體框架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語句。這似乎非常低效。

這是做這件事的最好方法嗎?我現在收到了一個新的要求,爲TABLE_B添加3個子表...所以我需要更多的包含...因此更多的選擇在幕後運行。

我明白我在做什麼的背後的邏輯..並且瞭解延遲加載目前在EF7中不受支持,但這似乎不是一種非常有效的做事方式,因爲我可以編寫一個存儲過程一口氣做到這一點。

是否有像這樣或某事的最佳實踐我沒有掌握如何使用EF7來做我需要的東西?

任何幫助或指導將不勝感激!

感謝

回答

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

根據你的使用情況,可以包括或ThenInclude一些導航在第一個查詢中加載TABLE_A。

加載擴展方法Source Link更多示例

+0

這對於收藏起什麼作用? TABLE_A是一個集合...並且每個實體都有一個TABLE_B列表。如果我是使用 '_context.Entry(<表A的一覽>)負載(B => b 。);' 我得到錯誤 '的IQueryable ' 不包含關於「表-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

哇,這是一個可怕的解決方案。如果我在一個視圖中渲染300個項目,並顯示來自10個FK表格的數據,我將在幕後有效地運行3000個查詢。 – rborob