2011-10-19 7 views
0

単純な選択クエリを実行するときに生成されるSQLを見ています。私は最初にナゲットのサンプルブログのコンテキストでコードを使用しています。select句でメソッドを使用するときのEnitityフレームワークのパフォーマンス

次が実行されている場合:

BlogContext _context = new BlogContext(); 
var comments = _context.Comments.Select(c => new CommentReadOnly {Author = c.Author}); 
var count = comments.Count(); 

次のSQLが生成されます。

カウントが期待されているSQLで行われ
SELECT 
    [GroupBy1].[A1] AS [C1] 
FROM (SELECT 
    COUNT(1) AS [A1] 
    FROM [dbo].[Comments] AS [Extent1] 
) AS [GroupBy1] 

は、しかし、私はこのように見えるようにコードを変更した場合:

BlogContext _context = new BlogContext(); 
var comments = _context.Comments.Select(c => new CommentReadOnly {Author = c.Author}); 
var count = comments.Count(); 

private CommentReadOnly ToCommentReadOnly(Comment comment) 
{ 
    return new CommentReadOnly 
    { 
    Author = comment.Author, 
    }; 
} 

次のSQLが生成されますcount

SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[PostID] AS [PostID], 
[Extent1].[Text] AS [Text], 
[Extent1].[Author] AS [Author] 
FROM [dbo].[Comments] AS [Extent1] 

は、コード内で行わ。

最初はIQueryableとして返され、2番目はIEnumerableと返される理由が考えられます。

SQLを実行せずに2番目のクエリをIQueryableとして返すことはできますか?

私はエンティティにクエリを行い、必要な型に変換できるジェネリックリポジトリレイヤを作成しています(上記の例では、いくつかの異なる '読み取り専用'オブジェクトがあるかもしれません)。私は、ページングが異なる状況で別のフィルタリングが行われるように、SQLを早く実行したくはありません。

+0

2つのコードスニペットはまったく同じではありませんか?クエリは '.Count()'で実行され、 '.Count()'の前にコードの違いは見られません。 – Slauma

答えて

0

これらの2つのクエリには違いはありません。しかし、クライアントがIQueryableオブジェクトをクライアントに戻して、クライアントがさらにフィルタリングを実行してそこからカウントを取得できるようにしたいと思います。

選択を行わずにオブジェクトを返すだけで、クライアントが残りの作業を行うことができます。

return _context.Comments 

クライアントは

0

は、私はあなたが機能ToCommentReadOnly()を実行し、あなたの2番目のクエリではと思います。このたIQueryableオブジェクトに追加フィルタリングを行うことができますので、これはSQLで完全に行うことができず、で終わりますオブジェクトへのLinq(IEnumerable)。

しかし、リポジトリからIQueryableを返すとします。これは推奨される方法ではありません。データにアクセスするコードは、問題に遭遇することのないリポジトリ内に隠されている必要があります。

リポジトリ(あなたのObjectContextをカプセル化する)が範囲外になった後、リポジトリから与えられたIQueryableの結果を列挙しようとしたとしましょう。 IQueryableはもう実行できないため、これはエラーをスローします。

リポジトリからIQueryableを公開した場合、リポジトリのエンドユーザは、リポジトリを追加することで回避したい独自のクエリを作成する際に自由に使えます。

したがって、リポジトリからIEnumerableを返すのは良いことです:)

+0

'IQueryable'とリポジトリ外のコンテキストリファレンスを公開することは*一般的には"推奨されていない方法 "です。このプラクティスとは反対に、多くの理由があります(シンプルさ、ViewModelへの直接投影、デスクトップアプリケーションでの大量のデータ仮想化、レイジーローディングなど)。 – Slauma

+0

一例として、クエリを最適化しようとしているときです。私たちのリポジトリでは、パフォーマンスのためにCompiledQueriesを使用しています。 IEnumerableではなくIQueryableを公開すると、リポジトリのユーザーがクエリを変更してプリコンパイルを使用すると、コンパイルは役に立たなくなります。また、IQueryableを使用することで、コードをEntity Frameworkに結合することもできます。リポジトリパターンの全体のアイデアは、永続的なメカニズムとは独立していることです。上位層のニーズに合ったデータ層からのPOCOまたはカスタムDTOを公開します。 –

+0

私は知っている:)これらは良い点であり、理論は常に良いと思う。しかし、「持続性メカニズムの独立性」とデータアクセスのカプセル化に関しては、(時間と開発の労力で)実用的な*コスト*はほとんど言及されていません。私のことを誤解しないで、私はあなたの点は決して正しいとは言いませんが、私はその点が常に正しいことに同意します。 – Slauma