2

遅延読み込みをエミュレートするには、Eager Loading を介して完全なオブジェクト グラフを再帰的にインクルードし、エンティティの読み込み時に関連データもすべて読み込まれるようにするメソッドが必要です。

MSDN ドキュメントから:

  • 単一の参照を含めるには: query.Include(e => e.Level1Reference)。
  • 単一のコレクションを含める場合: query.Include(e => e.Level1Collection)。
  • 参照を含めてから、1 レベル下の参照を含めるには: query.Include(e => e.Level1Reference.Level2Reference)。
  • 参照を含めてから 1 レベル下のコレクションを含めるには: query.Include(e => e.Level1Reference.Level2Collection)。
  • コレクションを含めてから、1 レベル下の参照を含めるには: query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Reference))。
  • コレクションを含めてから 1 レベル下のコレクションを含めるには、次のようにします。 query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection))
  • コレクションを含めてから、1 レベル下の参照を含めるには: query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Reference))。
  • コレクションを含めてから 1 レベル下のコレクションを含めるには、次のようにします。 query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection))
  • コレクション、参照、および参照を 2 レベル下に含めるには: query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Reference.Level3Reference))。
  • コレクション、コレクション、および 2 レベル下の参照を含めるには: query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection.Select(l2 => l2.Level3Reference)))。

質問:

新しいプロパティが追加されたかどうかに関係なく、必要なときにいつでもエンティティの深いオブジェクト グラフを取得できるように、ナビゲート可能なすべてのプロパティを再帰的に含めて、これを汎用リポジトリ メソッドに組み込むにはどうすればよいですか?

4

2 に答える 2

3

わかりました、これはあなたの要件をもう少し良く満たすはずの編集されたバージョンです:

private static void EnumerateAllIncludesList(DbContext context, IEnumerable entities, List<object> entitiesLoaded = null)
{
    if (entitiesLoaded == null)
        entitiesLoaded = new List<object>();

    foreach (var entity in entities)
        EnumerateAllIncludesEntity(context, entity, entitiesLoaded);

}

private static void EnumerateAllIncludesEntity(DbContext context, object entity, List<object> entitiesLoaded)
{
    if (entitiesLoaded.Contains(entity))
        return;

    entitiesLoaded.Add(entity);

    Type type = entity.GetType();
    var properties = type.GetProperties();

    foreach (var propertyInfo in properties)
    {
        var propertyType = propertyInfo.PropertyType;

        bool isCollection = propertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)) &&
                            !propertyType.Equals(typeof(string));

        if (isCollection)
        {
            var entry = context.Entry(entity);

            if(entry.Member(propertyInfo.Name) as DbCollectionEntry == null)
                continue;

            entry.Collection(propertyInfo.Name).Load();

            var propertyValue = propertyInfo.GetValue(entity);

            if (propertyValue == null)
                continue;

            EnumerateAllIncludesList(context, (IEnumerable)propertyValue, entitiesLoaded);
        }
        else if ((!propertyType.IsValueType && !propertyType.Equals(typeof(string))))
        {
            var entry = context.Entry(entity);

            if (entry.Member(propertyInfo.Name) as DbReferenceEntry == null)
                continue;

            entry.Reference(propertyInfo.Name).Load();

            var propertyValue = propertyInfo.GetValue(entity);

            if (propertyValue == null)
                continue;

            EnumerateAllIncludesEntity(context, propertyValue, entitiesLoaded);
        }
        else
            continue;
    }
}

これを次のように使用します。

using (var context = new MyContext())
{
    var result = context.People.Where(x => x.Id == 1).ToList();
    EnumerateAllIncludesList(context,result);
}
于 2013-03-22T14:40:10.523 に答える
0

モデル優先またはデータベース優先を使用する場合、T4 テンプレートを記述して、edmx モデルを使用して必要なものを生成できます。簡単ではありませんが、可能です。

于 2013-03-22T14:12:22.467 に答える