14

ナビゲーション プロパティを入力するための別の方法があるのはなぜだろうと思っていました。

Includeセット全体で作業する場合は、プロパティまたはコレクションのいずれかを呼び出すことができます。

ただし、単一のエンティティで作業する場合、項目がコレクション ( Collection) か単一参照 ( Reference) かによって、2 つの別々のメソッドを呼び出す必要があります。

これを回避する方法はありますか - これにより、必要以上に複雑になっています。そして、EFの設計中にこれが決定された理由を誰か説明できますか?

編集

さらに調べてみると、問題はさらに深刻です。私がやろうとしていたのは、単一のエンティティにコレクション/ナビゲーション プロパティをロードする一般的な方法を作成することです。これは、Include を使用してセット全体で簡単に実行できます。ただし、 と のメソッド シグネチャReferenceCollection少し異なります。

気にしないで、これらの呼び出しをアプリの周りに分散させる必要があります。

例えば

dbSet<T>().Include(e => e.Property).Include(e => e.Collection).Include(e => e.Collection.Property) 

すべてが機能しているようです。

ただし、単一エンティティの呼び出しは異なります。

context.Entry(entity).Reference(e => e.Property).Load();
context.Entry(entity).Reference(e => e.Property.Select(e => e.SubProperty)).Load();
context.Entry(entity).Collection(e => e.Collection).Load();
4

4 に答える 4

18

このメソッドの唯一の目的は、Include()クエリ時に関連データを明示的に積極的にロードすることです。

一方、このメソッドは、関連データEntry()だけでなく、コンテキストにアタッチされたエンティティの現在の状態を特定の制御を提供することを目的としています。Load()

Collectionこれが、Referenceとメソッドのいずれかを明示的に選択する必要がある理由ですProperty。それぞれが異なる機能セットを公開します (したがって、異なる型を返します)。

例えば:

  • スカラー( DbPropertyEntry) にはIsModified、値が 'x' から 'y' に変化したかどうかを示すプロパティが含まれています (たとえば)。

  • 参照( DbReferenceEntry) にはIsLoaded、参照されたデータがデータベースからすでにロードされているかどうかを示すプロパティが含まれています。

  • 参照コレクション( ) は(したがってDbCollectionEntry) から派生します。これは、そのデータを反復処理できることを意味します。ただし、コレクション内のアイテムごとに異なる可能性があるため、プロパティを含めることはできません。ICollectionIEnumerableIsModified

それでも、 のみに関心がLoad()ある場合は、ポリモーフィックMember()メソッド (DbMemberEntry上記のすべての型の基本型を返す) を利用して、エントリが "読み込み可能" かどうかを確認できます。

var memberEntry = this.Entry(entity).Member("NavigationProperty");

if (memberEntry is DbCollectionEntry collectionMember)
    collectionMember.Load();

if (memberEntry is DbReferenceEntry referenceMember)
    referenceMember.Load();
于 2013-08-06T08:01:50.370 に答える
4

次の方法で実行できます。

1.- コレクションを含むエンティティをロードします。

MyClass myObject = dbContext.MyClasses
                    .Include(cls => cls.ObjectCollection)
                    .Single(cls => cls.Pk == entityPk);

2.- 次に、そのオブジェクト Entry を取得し、コレクション オブジェクトに必要なプロパティを読み込むように EF に指示する必要があります。

dbContext.Entry(myObject).Collection("ObjectCollection").Query().Include("ReferenceClass").Load(); 

参考文献:

http://msdn.microsoft.com/en-us/data/jj574232#explicitFilter

于 2014-10-30T10:03:03.873 に答える
1

"Include" 構文 FindAsync をサポートできるようにプロパティ式を引き続きサポートする場合は、次のソリューションで、参照されたプロパティの PropertyInfo を取得し、使用して、必要な構文をExpression.Convertサポートできるようにしますcontext.Entry(entity).Member(e => e.Property).Load()

次の 2 つのクラスを名前空間に追加し、usingそれをクラスに追加します。

public class MemberEntry
{
    /// <summary>
    /// If this MemberEntry refers to a CollectionEntry, this will be not null
    /// </summary>
    public CollectionEntry? CollectionEntry { get; init; }
    /// <summary>
    /// If this MemberEntry refers to a ReferenceEntry, this will be not null
    /// </summary>
    public ReferenceEntry? ReferenceEntry { get; init; }
    public MemberEntry(CollectionEntry collectionEntry)
    {
        this.CollectionEntry = collectionEntry;
    }
    public MemberEntry(ReferenceEntry referenceEntry)
    {
        this.ReferenceEntry = referenceEntry;
    }
    //
    // Summary:
    //     Loads the entity or entities referenced by this navigation property, unless Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.IsLoaded
    //     is already set to true.
    //     Note that entities that are already being tracked are not overwritten with new
    //     data from the database.
    public void Load()
    {
        if (this.CollectionEntry != null)
        {
            this.CollectionEntry.Load();
        }
        else
        {
            this.ReferenceEntry!.Load();
        }
    }

    //
    // Summary:
    //     Loads the entity or entities referenced by this navigation property, unless Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.IsLoaded
    //     is already set to true.
    //     Note that entities that are already being tracked are not overwritten with new
    //     data from the database.
    //     Multiple active operations on the same context instance are not supported. Use
    //     'await' to ensure that any asynchronous operations have completed before calling
    //     another method on this context.
    //
    // Parameters:
    //   cancellationToken:
    //     A System.Threading.CancellationToken to observe while waiting for the task to
    //     complete.
    //
    // Returns:
    //     A task that represents the asynchronous operation.
    public Task LoadAsync(CancellationToken cancellationToken = default)
    {
        if (this.CollectionEntry != null)
        {
            return this.CollectionEntry.LoadAsync(cancellationToken);
        }
        else
        {
            return this.ReferenceEntry!.LoadAsync(cancellationToken);
        }
    }
}

public static class EntityEntryExtensions
{
    public static MemberEntry Member<TEntity>(this EntityEntry<TEntity> entityEntry, Expression<Func<TEntity,object?>> prop)
        where TEntity : class
    {
        var propInfo = GetPropertyInfo(prop);
        MemberEntry memberEntry;
        if (propInfo.PropertyType.IsAssignableTo(typeof(IEnumerable)))
        {
            Expression converted = Expression.Convert(prop.Body, typeof(IEnumerable<object>));
            Expression<Func<TEntity, IEnumerable<object>>> collProp = Expression.Lambda<Func<TEntity, IEnumerable<object>>>(converted, prop.Parameters);
            memberEntry = new(entityEntry.Collection(collProp));
        }
        else
        {
            memberEntry = new(entityEntry.Reference(prop));
        }
        return memberEntry;
    }
    
    private static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
    {
        Type type = typeof(TSource);
        if (propertyLambda.Body == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a method, not a property.",
                propertyLambda.ToString()));
        if (propertyLambda.Body is MemberExpression member)
        {
            if (member.Member == null)
                throw new ArgumentException(string.Format(
                    "Expression '{0}' refers to a field, not a property.",
                    propertyLambda.ToString()));
            if (member.Member is PropertyInfo propInfo)
            {
                if (type != propInfo.ReflectedType &&
                !type.IsSubclassOf(propInfo.ReflectedType!))
                    throw new ArgumentException(string.Format(
                        "Expression '{0}' refers to a property that is not from type {1}.",
                        propertyLambda.ToString(),
                        type));
                else
                    return propInfo;
            }
        }
        throw new ArgumentException(string.Format(
                    "Expression '{0}' doesn't refer to a class property of {1}.",
                    propertyLambda.ToString(),
                type));
    }
}

同期:

this.Entry(myObject).Member(_ => _.MyProperty).Load();

非同期:

await this.Entry(myObject).Member(_ => _.MyProperty).LoadAsync();
于 2022-02-18T05:02:48.370 に答える