2012-01-19 11 views
2

ここに問題があるコードがあります。私は既存のデータベースからモデル化されたEDMXを使用しています。ここでLINQ with Where and Allはデータをフィルタリングしない - このクエリで何が問題になっていますか?

// All orders completely shipped Grouped by RefId 

       var RefIdsWithAllShippedOrders = mydbcontext.OrderDetails 
        .Where(s => s.Application.CustomerID == "MSFT") 
        .GroupBy(o => o.RefId) 
        .Where(t => t.All(i => i.Status.Description.ToUpper() == "SHIPPED")) 
        .Select(g => g.Key); 

    // Iterate through the RefIds 
    foreach (var refid in RefIdsWithAllShippedOrders) 
       { 

       // Gather all the orders that have the same RefIds 
       var OrdersForThisRefid = (from o in mydbcontext.OrderDetails 
             where o.RefId == refid 
             select o).AsEnumerable(); 

//gather all the orders with at least one Canadian recipient 
var orderswithcandianrecipients = from o in OrdersForThisRefId 
            where o.OrderRecipients.All(w=> w.Country.Trim().ToUpper() == "CANADA") // ****            
            select o; 
      // Print RefIds of the orders that have at least one Canadian recipient 
      foreach (var eachorder in orderswithcandianrecipients) 
      { 
        Console.WriteLine(eachorder.RefId); 
      } 

     } 

は、私が持っているスキーマです:私は得ることを望んだ

ORDERDETAILS

RefId  OrderId (PK) 
ABC001  00001 
ABC001  00002 
ABC001  00003 
ABC002  00004 
ABC002  12355 

ORDER受信者

PK  OrderID (FK) NAME   COUNTRY 
1  00001   LINCOLN  USA 
2  00001   JEFFERSON USA 
3  00001   WASHINGTON CANADA 
4  00001   FRANKLIN  USA 
5  00002   GRANT  USA 
6  00002   WILSON  USA 
7  12355   FORD   CANADA 
8  12355   JOHNSON  USA 

結果は、その注文が含まれていvarタイプです少なくともカナダ人の受取人が少なくとも1人いること。上記の例では、それが受注コード= 00001と12355

コードと受注だろう、私が*が付いているWhereAllフィルタを尊重していないようです。すべての注文を返します。何が間違っているのか理解してください。どうもありがとうございます。

答えて

4

私はあなたがほしいと思うと思うAnyでないAllAllを使用すると、注文のすべての受取人はカナダ人でなければならないと言っています。 Anyはカナダ人の受取人が少なくとも1人いる注文をします。

Allについての別の警告。条件に合格するすべてのアイテムが検索されず、条件に合致しない最初のアイテムが検索されます。私は1つに、ループの内側に2つのクエリを結合し、その後cadrell0の答えで説明したようにAnyを使用することになり、あなたがゼロのアイテムを持っている場合、したがって、あなたは条件を失敗しているいずれかを持っていない、とAllは常にtrue

+0

ありがとうございます@ cadrell0。しかし、カナダの受取人がいなくても、すべての注文を返すのはなぜですか? – FMFF

+1

私は自分の答えを更新しました。私は注文00002を説明することはできませんが、それは他のものを説明する必要があります。 – cadrell0

+0

あなたは正しいです。これはQA /開発データベースであり、私はOrderDetailsテーブル内のすべてのオーダーについて受信者が設定されていません。つまり、常にTrueを返します。私にcaldrell0を教えていただきありがとうございます。だからAnyはそのような場合に動くはずですか? – FMFF

2

を返します。

var orderswithcandianrecipients = 
    from o in mydbcontext.OrderDetails 
    where o.RefId == refid && o.OrderRecipients.Any(
     w => w.Country.Trim().ToUpper() == "CANADA")   
    select o; 

問題は、データがメモリにロードされるようにする最初のクエリでAsEnumerable()を使用することのようです。しかし、クエリにOrderRecipientsを含めないので、このコレクションは空になります。 2番目のクエリはメモリ(LINQ to Objects)で実行されます。したがって、Allは空のコレクションの場合は常にtrueなので、すべての注文を返します。 Anyで置き換えると、空のコレクションの場合はAnyが常にfalseであるため、おそらく注文はまったく返されません。

2つのクエリを組み合わせることにより、データベース全体でクエリが実行され、ansdは正しい結果を返さなければなりません。

+0

ありがとう@Slauma。最初のクエリにはAsEnumerable()が必要です。コード内の別の場所でこれを行う必要があったからです。 'TotalStatementCount = OrdersForThisRefid.Sum(w => { int result; Int32.TryParse(w。UserDef1、出力結果);戻り値: ; }); ' AsEnumerable()を使用しないと可能ですか? – FMFF

+1

@FMFF:いいえ、EFはこれをSQLに変換して例外をスローすることはできません。おそらく、それが機能するように書き直すことは可能です(これを明確にしたい場合は、新しい質問をより良くする)。もちろん、最初のクエリで 'from o in mydbcontext.OrderDetails.Include(" OrderRecipients ")'と書くこともできますが、これはフィルタリングされていないすべてのOrderRecipientsコレクションをメモリにロードするので高価になる可能性があります。 – Slauma

+0

はい、私はここに尋ねました - http://stackoverflow.com/questions/8917303/linq-summing-numbers-stored-as-string フィルタリングされていないOrderRecipientsをメモリにロードすることは問題になりません。それらのうち200万以上があります。 :-)もう一度、明確にすることに感謝します。 – FMFF

関連する問題