2017-05-30 7 views
-1

次の結果行が生成されず、Firstが例外をスローするようなクエリをEFが生成するのはなぜですか?なぜこのEFクエリは結果にCountを含めるにもかかわらず結果を返しませんか?

IQueryable<EntityName> repo = GetQuery<EntityName>(); 
IQueryable<EntityName> query = repo.Where(x => x.Discriminator == 1); 
var result = repo.Select(x => new 
{ 
    TotalRecords = query.Count(), 
    Results = query.Skip(request.Skip).Take(request.Take).ToList() 
}).First(); 

このトリックでは、EFでの1回のデータベース呼び出しで複数のクエリを実行できます。私は任意のリポジトリrepoを呼び出し、各プロパティがサブクエリである新しいオブジェクトを返します。これは、query IQueryableにレコードがある限り機能します。しかし、queryにレコードがない場合、何も返されない(つまり、query.Count()は結果に含まれていない)ことに驚きました。私は、このようなクエリは、Count()に関係するので、queryにエンティティがなくても結果行を生成するはずだと考えましたが、何も返しません。私はこれが、フードの下で単一の平坦な結果セットを生成しなければならないEFと関係があると考えています。

+0

「選択」内に何があるかは関係ありません。結果のカウントは入力セットと常に同じです。 'First'(または' Take(1) ')は、最大1、すなわち0または1に制限することができます。これは基本的にEFではなくSQLクエリの動作です。 –

答えて

1

それはCount方法は、常に値を返すことは事実だが、あなたのトリックに問題はそれが外selectクエリ(repo.Select(x => ...)の一部であるということですので、結果セットのカーディナリティが含まれるレコードの数によって制御されます外側のクエリではrepo - 空の場合、結果は空になるため、FirstOrDefaultnullを返し、内部のサブクエリはまったく実行されません。

異なるデータベースには、このような問題を解決するための異なるメカニズムを持っている - たとえば、Oracleはdualと呼ばれる特殊なシングルレコードテーブルを使用しているだけでなく(、SQL ServerがFROMなどなしSELECTを使用できますが、EFは一般的なものであるため、それはそれらのいずれかを使用することはできません技術的には、すべてが標準的な方法で抽象化され、実際の実装が実際のプロバイダに委譲されていても、実行されていない場合)。

まだLINQは、DefaultIfEmptyメソッドを使用して、セットが強制的に1レコード以上を返すような方法(EFでサポート)を提供します。 Selectオペレータの前に外側のクエリに適用する必要があります。

var result = repo.DefaultIfEmpty().Select(x => ... 

サブクエリがxとは全く無関係なので、あなたが使用することにより、単一の外の結果を生成するために使用されるdbテーブルを排除することができます

var result = repo.Where(_ => false).DefaultIfEmpty().Select(x => ... 

repoは、DbContextから正確にIQueryProviderを取得した時点で、どれもIQueryable<T>となります。

関連する問題