2011-06-22 7 views
2

Books、TradingDesks、ProductInfosの結合を実行するこのクエリがあります。このコレクションのデータは膨大です。強調表示された行(on b.Id equals p.RiskBookId)LINQクエリヘルプ

var queryJoin = from b in books.Values 
            join d in tradingDesks.Values 
             on b.TradingDeskId equals d.Id 
            join p in ProductInfos.Values 
             **on b.Id equals p.RiskBookId** 
            select new { p, Book = b.Name, TradingDeskName = d.Name }; 

、私はまた(on b.Id equals p.RiskBookId || p.RiskBookId == 0)、同様に別の条件を追加します。どのようにこのlinqの構文でこれを行うのですか?

私はこの

var queryJoin = from b in books.Values 
       from d in tradingDesks.Values.Where(x => x.Id == b.TradingDeskId) 
       from p in cachedProductInfos.Values.Where(y => y.RiskBookId == b.Id) 
       select new { p, Book = b.Name, TradingDeskName = d.Name }; 

のように照会してみましたが、この場合には、クエリは永遠に実行され、私はメモリ不足。 。だから私はこの方法でそれをフレーミング推測が狂った何か:(任意の助けが高く評価され

を行い

おかげ マニ実際

+0

これは完全にLINQツーオブジェクト、私は見ていないように思わどこLINQからSQLへ適合する – Aducci

答えて

2

、Enumerable.Joinにこれらの呼び出しは、物事を速くするために舞台裏でハッシュテーブルを使用しています。 .Whereに切り替えると、そのハッシュメリットは得られません。明示的にハッシュを使用して同じ効果を得ることができます。

ILookup<int, string> deskNameLookup = tradingDesks.Values 
    .ToLookup(
    d => d.Id, 
    d => d.Name 
); 

ILookup<int, ProductInfo> infoLookup = ProductInfos.Values 
    .ToLookup(p.RiskBookId); 

foreach(b in books.Values) 
{ 
    foreach(dName in deskNameLookup[b.TradingDeskId]) 
    { 
    foreach(p in infoLookup[b.Id].Concat(infoLookup[0])) 
    { 
     var x = new {p, Book = b.Name, TradingDeskName = dName}; 
    } 
    } 
} 
+0

Davidさんありがとうございます。これはもっと有望ですが、このクエリ式をIQueraybleとして使用しています。これをIQueryableにどのようにロードすることができるかについての考え方はありますか? –

+0

これは答えとして表示されていますが、これは問題を解決しないものです。 –

-1

join d in tradingDesks.Values 
    on (b.Id equals p.RiskBookId || p.RiskBookId equals 0) 

または

on (b.Id == p.RiskBookId || p.RiskBookId == 0) 

完全に正常に動作するはずです

ザ・参加

は真の条件が必要です。

on <expression> 

(b.Id equals p.RiskBookId || p.RiskBookId == 0) 

ちょうどように評価すべきであるtrueまたはfalseを返すので、参加します。

+0

これはコンパイルされません!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! books.Values にb.TradingDeskIdにtradingDesks.Values でDに参加BからVAR queryJoin =は(p.RiskBookId || p.RiskBookIdが0に等しいb.Id)d.Id がオンcachedProductInfos.Values のpに参加等しいです 新しい{p、Book = b.Name、TradingDeskName = d.Name}を選択します。 –

+0

いいえ、これはコンパイルされません。 –

+0

ああ、LinqはSQLに似ているからね。 :) –

0

equalsは、単一の比較を行うためにのみ使用できます。

他の人があなたの状況に合わせて最適化された方法を提供できるかもしれませんが、equals条件に追加することはここでの解決策ではありません。しかし、データのサイズが明らかに問題であるため、一種の並べ替えローディングとキャッシングメカニズムによって、単一のクエリの本体内からすべてのデータを取り出すのではなく、別の方法でデータにアプローチするのが最善の方法です。

0

は、これを試して少し逐語しかし、あなたはそれを説明するように動作するはずです:元のクエリで

var queryJoin = 
    from b in books.Values 
    join d in tradingDesks.Values on b.TradingDeskId equals d.Id 
    let p = 
     from pi in ProductInfos.Values 
     where (b.Id == pi.RiskBookId) || (pi.RiskBookId == 0) 
     select pi 
    where p.Any() 
    select new 
    { 
     p, 
     Book = b.Name, 
     TradingDeskName = d.Name 
    }; 
+0

いいえ。これはどちらもうまくいきません。タイムアウト! :( –

+0

問題は '(pi.RiskBookId == 0)'である可能性があります。その条件でレコードが大量にある場合は、データに依存します –

+0

あなたは正しいです。別の角度から考えると、必要なものはすべてProductInfoコレクションの外部結合。まだ同じものに取り組んでいますが、解決策はまだありません.... –

1

あなたの代わりに労働組合としてそれをフレーミング試みることができる単一の参加:

var baseQuery = 
    from book in books.Values 
    join desk in tradingDesks.Values on book.TradingDeskId equals desk.Id 
    select new {book, desk}; 

var conditionOne = 
    from baseQ in baseQuery 
    join productInfo in ProductInfos.Values on baseQ.book.Id equals productInfo.RiskBookId 
    select new 
    { 
     productInfo, 
     Book = baseQ.book.Name, 
     TradingDeskName = baseQ.desk.Name 
    }; 

var conditionTwo = 
    from baseQ in baseQuery 
    join productInfo in ProductInfos.Values on book.Id equals 0 
    select new 
    { 
     productInfo, 
     Book = baseQ.book.Name, 
     TradingDeskName = baseQ.desk.Name 
    }; 

var result = conditionOne.Union(conditionTwo);