0

IQueryableIEnumerable と、Entity Framework との使用方法の相互交換について少し混乱しています。この件についてできる限り多くのグーグル検索を試みましたが、役に立たなかったようです。これが私の状況です。

私は関数を持っています(MyClassはですEntityObject):

IEnumerable<MyClass> GetMyClasses(int id) {
    return GetQuery().Where(p => p.Id==id);
}

IQueryable<MyClass> GetQuery() {
    // returns an IQueryable list here
}

今私の質問はです。ここで ではなく IEnumerable を返しているIQueryable場合、ステートメントがToList()で実行されると、生成された基になる SQL はステートメントを考慮してId == idフィルター項目のみを返すか、データベースのすべてのオブジェクトをメモリに取り込みます。そのリストでWhere句を実行しますか?

これを説明するリソースへのヘルプ、またはポインタさえありますか?

4

3 に答える 3

1

ステートメントがToList()で実行されると、生成された基になる SQL は Id == id ステートメントを考慮し、フィルター項目のみを返します。

簡単な答えは「はい」です。

対応するものはEnumerable.ToList<T>(this IEnumumerable<T> e)ありませんIQueryable<T>

GetMyClassesメソッド内のすべてが として動作しますIQueryable<T>が、後で追加された制限はインメモリになります。

IEnumerable<MyClass> GetMyClasses(int id) {
    return GetQuery().Where(p => p.Id==id); // this always will work as IQueryable and handled by provider (in case of EF - the DB query will be performed)
}

IEnumerable<MyClass> MoreRestrictions(int id) {
     return GetMyClasses(id)
         .ToList(); // result list will be filtered by Id
}

IEnumerable<MyClass> MoreRestrictions(int id) {
     return GetMyClasses(id)
         .Where(x=>x.IsActive) // this where will be performed in memory on results filtered by Id.
         .ToList(); 
}

メソッドToListWhereは、次のように動作します

//There is only one implementation of ToList()
public List<T> ToList<T>(this IEnumerable<T> e) 
{
    var list = new List<T>();
    var enumerator = e.GetEnumerator();
    while (enumerator.MoveNext())
    {
        var item = e.Current;
        list.Add(item);
    }
    return list;
}

//Implementation for IEnumerable
public IEnumerable<T> Where<T>(this IEnumerable<T> e, Predicate predicate) 
{
    var enumerator = e.GetEnumerator();
    while (enumerator.MoveNext())
    {
        var item = e.Current;
        if (predicate(item))
            yield return item;
    }
}

//Implementation for IQueryable
public IQueryable<T> Where<T>(this IQueryable<T> e, Expression<Predicate> predicate) 
{
    MethodBase method = ...; // create generic method of Queryable.Where()
    return e.Provider
        .CreateQuery<T>(Expression.Call(null, method, e.Expression, Expression.Quote(predicate)));
}

GetEnumeratorIQueryableのメソッドは、クエリの実体化を行います。

于 2013-03-22T00:58:23.083 に答える
1

この記事は役に立ちます: IQueryable vs IEnumerable in LINQ-to-SQL

その記事を引用すると、'MSDN のドキュメントによると、IQueryable で行われた呼び出しは、代わりに内部式ツリーを構築することによって動作します。「IQueryable(Of T) を拡張するこれらのメソッドは、クエリを直接実行しません。代わりに、それらの機能は、累積クエリを表す式ツリーである Expression オブジェクトを構築することです。」

式ツリーは、C# および .NET プラットフォームで非常に重要な構成要素です。(これらは一般的に重要ですが、C# では非常に便利です。) 違いをよりよく理解するには、公式の C# 5.0 仕様のステートメント の違いについて読むことをお勧めします。ラムダ計算に分岐する高度な理論的概念の場合、式を使用すると、ファーストクラス オブジェクトとしてメソッドをサポートできます。IQueryable と IEnumerable の違いは、この点に集中しています。IQueryable は式ツリーを構築しますが、IEnumerable は構築しません。少なくとも、Microsoft の秘密の研究所で働いていない私たちにとっては一般的な用語ではありません。

これは、プッシュとプルの観点からの違いを詳述する別の非常に役立つ記事です。(「プッシュ」対「プル」によって、データ フローの方向を参照しています。.NET および C# のリアクティブ プログラミング テクニック

ステートメント ラムダと式ラムダの違いを詳しく説明し、式トレスの概念について詳しく説明している非常に優れた記事を次に示します。C# デリゲート、式ツリー、ラムダ ステートメントとラムダ式の再検討です。.

于 2014-03-14T02:17:50.110 に答える
1

あなたはこれを複雑にしすぎています。次の点を考慮してください。

public class Base { }

public class Derived : Base { }

public Base Method() {
    return GetOtherMethod();
}

public Derived GetOtherMethod()
{
    return new Derived ();
}

からの戻り値の特性について疑問に思っていますMethod。のインスタンスになりますが、にキャストしない限りDerived、 としてしか使用できません。BaseDerived

したがって、としてのみ使用できるGetMyClassesが返されます。IQueryable<MyClass>IEnumerable<MyClass>

于 2013-03-22T01:06:04.343 に答える