2016-07-15 3 views
0

私はEF7(CORE)を使い始めたばかりで、次のことを正しく実装するのに苦労しています。私は孫のテーブルを持っている複数の子テーブルを持つテーブルを持っているとしましょう(これらは順番に外部キーテーブルを持っています)。私はすべてのものへのアクセスを望んでいた場合、私は今、私は私の子テーブルのすべてが含まれるように含まれています...が、私はそれが舞台裏発射SQLを見てチェーン化の必要性を理解し、このエンティティフレームワーク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) 

ようなものが必要だろう11のSQL文を実行しています。これはひどく非効率的です。

これを行うには、これが最善の方法ですか?私は今、TABLE_Bに3つ以上の子テーブルを追加する新しい要件を受けました。もっと多くのインクルードが必要になります。

私がやっていることの背後にある論理を理解しています。遅延読み込みは現在EF7ではサポートされていませんが、これは非常に効率的な方法です。一度にやります。

このようなことにはベストプラクティスがありますか?EF7を使用して必要なことを行う方法については把握していませんか?

ご迷惑をおかけして申し訳ございません。 、あなたはナビゲーションの各プロパティを必要なときに、その後

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

おかげ

答えて

0

プロジェクトに、この拡張メソッドを追加するには、Loadメソッドは、EF 6.xで存在するが、まだEFコアに実装されていません前に(任意のナビゲーションプロパティのために一度だけ)休閑としてメソッドの最初の呼び出しの負荷を使用します。あなたのユースケースに応じて、

//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 ' TABLE_B」の定義が含まれていません取得します'拡張メソッド' TABLE_B '型' IQueryable 'の最初の引数を受け入れることはできませんでした – rborob

+0

_context.Entry単一のオブジェクトを取得し、最初にすべてのTABLE_Aリストをロードし、TABLE_Aリスト内の項目ごとに必要なときはいつでも、 :var item = TABLE_A.First(); <実際には、LazyLoadiningに似ていますが、明示的なロードナビゲーションに似ています。 –

+0

うわー、それはひどい解決策です。ビュー内でアイテム300個をレンダリングし、10個のFKテーブルからデータを表示すると、3000個のクエリが効果的に実行されます。 – rborob

関連する問題