2016-05-06 14 views
2

は、次の関数を考えてみましょう:Func <S、IQueryable <R>>の代わりにQueryable.SelectMany(...)オーバーロードでFunc <S、IEnumerable <R>>を使用するのはなぜですか?

IQueryable<Bar> foo(IEnumerable<IQueryable<Bar>> sources) 
{ 
    return 
     from source in sources.AsQueryable() 
     from bar in source 
     where bar.Xzy == 123 
     select bar; 
} 

直感的に、私はこれは、各ソースのコンテキストで「から... ...選択」という表現を実行するために期待されます。しかし、代わりに "from bar in ..."部分だけをソースに対して実行し、その代わりに "where ... select"部分をLINQ-to-Objectsクエリとして実行すると思います。結果として、SomeTableのすべての行は、「where」条件に一致するものだけではなく、各ソースから取得されます。

SelectManyを呼び出すと、暗黙的にIEnumerable <Bar>に変換されるため、一見したところです。私は実装がどのように見えるかはわかりませんが、代わりにFunc < S、IQueryable <R> >を受け入れるのは意味がありませんので、Where ... select式はIQueryableプロバイダに渡されますか?

+0

'source.SomeTable'の種類は何ですか? 'foo'の戻り値の型を' IQueryable 'に変更するとどうなりますか? – Lee

+0

@Lee、申し訳ありませんが、SomeTableプロパティはこの例では意味がないと思います。私は "source.SomeTable"を "source"にします。戻り値の型をIQueryable に変更しても、クエリの動作は変更されません。 – Aaron

+0

'IEnumerable 'オーバーロードが 'IEnumerable 'を返し、 'IQueryable'オーバーロードが' IQueryable 'を返すので、戻り値の型は異なります。したがって、戻り値の型が 'IQueryable 'に変更され、 'SelectMany'の' IEnumerable'オーバーロードが選択された場合、関数はコンパイルに失敗します。 – Lee

答えて

1

私は、コンパイラがどのようにクエリを解釈するのかと思います。

sources.AsQueryable() 
     .SelectMany(source => source) 
     .Where(bar => bar.Xzy == 123) 
     .Select(bar => bar) 

極めて重要な、あなたのフィルタが最初の各ソースを列挙した結果に基づいて動作:何それは実際にあなたのクエリを回すのは、このような何か(厳密に左から右への解析)です。

AsQueryable()はこれ以上照会可能、彼らはすでにされているよりも、あなたのソースを作っていないので、それはあなたのソースのが照会可能列挙を作っている、とあなたはとにかく設定することを照会されていない、実際には冗長であることにも注意してください、あなたは個々のソースを照会しています。

は、あなたが実際にこのようなより多くので欲しい、私は思う:

sources.SelectMany(source => source.Where(bar => bar.Xzy == 123)) 

これは相対的な「オーダー・オブ・優先」条項の解釈を変更します。

LINQ構文を使用して後者をどのように工夫するかは、実際はわかりません。

UPDATE:実は、ここに一つの方法です:

from source in sources 
let qsource = (from bar in source 
       where bar.Xzy == 123 
       select bar) 
from result in qsource 
select result 

私は、一般的に、まさにこの理由のための拡張メソッドを使用して、非自明なクエリを作ることを好む傾向にあります。

+0

ありがとう、ちょうどあなたの更新された答えのようなLINQ式を使用して巻いた。なぜ元のクエリが私が期待したことをしなかったのか、私の頭を包み込むようにしようとしています。私はもともと私の "本当の"クエリでAsQueryable()呼び出しを追加しました。それは、Enumerable.SelectManyの代わりにQueryable.SelectManyの使用を強制することで、私の問題を解決しようとしていると思いました。 – Aaron

関連する問題