web-dev-qa-db-ja.com

LINQ:結合とグループ化の組み合わせ

結合とグループを組み合わせたクエリがありますが、問題があります。クエリは次のようなものです。

 var result = from p in Products                         
 join bp in BaseProducts on p.BaseProductId equals bp.Id                    
 group p by p.SomeId into pg                         
 select new ProductPriceMinMax { 
       SomeId = pg.FirstOrDefault().SomeId, 
       CountryCode = pg.FirstOrDefault().CountryCode, 
       MinPrice = pg.Min(m => m.Price), 
       MaxPrice = pg.Max(m => m.Price),
       BaseProductName = bp.Name  <------ can't use bp. 
 };

ご覧のとおり、ProductsテーブルとBaseProductsテーブルを結合し、Productテーブルのidでグループ化します。しかし、結果のProductPriceMinMaxでは、BaseProductsテーブルのプロパティbp.Nameも必要ですが、bpがわかりません。

私が間違っていることを知っていますか?

ありがとう!

50
L-Four

これをやったら

group p by p.SomeId into pg  

最初のfromで使用されている範囲変数にアクセスできなくなりました。つまり、pまたはbpについて話すことはできなくなり、pgについてのみ話すことができます。

現在、pggroupであるため、複数製品が含まれています。特定のpgグループ内のすべての製品は同じSomeIdを持っています(グループ化したものだからです)が、それらがすべて同じBaseProductIdを持っていることを意味するかどうかはわかりません。

ベース製品名を取得するには、pgグループ(SomeIdおよびCountryCodeで行っているように)の特定の製品を選択する必要があり、then結合BaseProductsに。

var result = from p in Products                         
 group p by p.SomeId into pg                         
 // join *after* group
 join bp in BaseProducts on pg.FirstOrDefault().BaseProductId equals bp.Id         
 select new ProductPriceMinMax { 
       SomeId = pg.FirstOrDefault().SomeId, 
       CountryCode = pg.FirstOrDefault().CountryCode, 
       MinPrice = pg.Min(m => m.Price), 
       MaxPrice = pg.Max(m => m.Price),
       BaseProductName = bp.Name  // now there is a 'bp' in scope
 };

そうは言っても、これは非常に珍しいように見えるので、実際に取得しようとしているものを検討してください。

87
AakashM

このようにしました:

from p in Products                         
join bp in BaseProducts on p.BaseProductId equals bp.Id                    
where !string.IsNullOrEmpty(p.SomeId) && p.LastPublished >= lastDate                         
group new { p, bp } by new { p.SomeId } into pg    
let firstproductgroup = pg.FirstOrDefault()
let product = firstproductgroup.p
let baseproduct = firstproductgroup.bp
let minprice = pg.Min(m => m.p.Price)
let maxprice = pg.Max(m => m.p.Price)
select new ProductPriceMinMax
{
SomeId = product.SomeId,
BaseProductName = baseproduct.Name,
CountryCode = product.CountryCode,
MinPrice = minprice, 
MaxPrice = maxprice
};

編集:AakashMのバージョンを使用しました。パフォーマンスが優れているためです。

25
L-Four

私はあなたと同じ問題に出会いました。

2つのtablesresultt1オブジェクトにプッシュし、t1グループ化します。

 from p in Products                         
  join bp in BaseProducts on p.BaseProductId equals bp.Id
  select new {
   p,
   bp
  } into t1
 group t1 by t1.p.SomeId into g
 select new ProductPriceMinMax { 
  SomeId = g.FirstOrDefault().p.SomeId, 
  CountryCode = g.FirstOrDefault().p.CountryCode, 
  MinPrice = g.Min(m => m.bp.Price), 
  MaxPrice = g.Max(m => m.bp.Price),
  BaseProductName = g.FirstOrDefault().bp.Name
};
10
Milkker