2

そこで私は最近、式ではなく拡張メソッドにを指定するFunc<T, TResult>ことで、EntityFrameworkがプロジェクションをSQLに変換しないように強制できることを発見しました。.Select()これは、クエリされたデータを変換する場合に役立ちますが、その変換はデータベースではなくコードで行う必要があります。

たとえば、EF5の新しい列挙型サポートを使用してそれをDTOの文字列プロパティに投影しようとすると、失敗します。

results.Select(r => new Dto { Status = r.Status.ToString() })

これはうまくいくでしょう:

results.Select(new Func<Record, Dto>(r => new Dto { Status = r.Status.ToString() }));

最初の(式)の場合、EFはStatus.ToString()をSQLデータベースが実行できるものに変換する方法を理解できないためですが、この記事のとおり、Func述語は変換されません。

これが機能するようになったら、次の拡張メソッドを作成することはそれほど大きな飛躍ではありませんでした。

public static IQueryable<T> Materialize<T>(this IQueryable<T> q)
{
    return q.Select(new Func<T, T>(t => t)).AsQueryable();
}

だから私の質問は-これを使用するときに注意すべき落とし穴はありますか?パフォーマンスに影響はありますか?この何もしないプロジェクションをクエリパイプラインに挿入するか、EFが.Where()句をサーバーに送信しないようにして、すべての結果をネットワーク経由で送信することによってですか?

.Where()サーバー上の結果をフィルター処理するメソッドを引き続き使用することを目的としていますが、プロバイダーがプロジェクションをSQLServerに変換しようとしないよう.Materialize()に前に使用.Select()します。

return Context.Record
    .Where(r => // Some filter to limit results)
    .Materialize()
    .Select(r => // Some projection to DTO, etc.);
4

2 に答える 2

2

単に使用AsEnumerableするだけでも同じことができます。

return Context.Record
              .Where(r => // Some filter to limit results)
              .AsEnumerable() // All extension methods now accept Func instead of Expression
              .Select(r => // Some projection to DTO, etc.);

IQueryableまた、Materializeメソッドは実際にはIQueryable別のクエリに変換されていないため、戻る理由はありません。ただIEnumerableです。

パフォーマンスの面では、あなたは大丈夫なはずです。マテリアライズ前のすべてがデータベースで評価され、マテリアライズ後のすべてがコードで評価されます。さらに、あなたと私の例の両方のクエリでは、まだ実行が延期されています-何かがクエリを列挙するまで実行されません。

于 2012-09-12T12:11:05.083 に答える
0

ただし、問題が1つあります。それは、クライアントにフェッチされる列の数です。最初のケースでは、それは次のようなものになりselect Status from Recordますselect Status, field2, field3, field4 from Record

于 2013-10-04T14:22:40.497 に答える