「group by」文を使用する linq の結果であるオブジェクト IGrouping について疑問があります。
データベースに Products と Responses の 2 つのテーブルがあり、1 と * の関係があります。Responses テーブルには、製品のレートである FinalRate という列があります。製品には、n 個の応答または率を指定できます。
FinalRate の合計を完了したレートの数で割って Products の注文を取得したいと考えています。つまり、平均レートが高いものから低いものへと降順で並べます。
コードで(質問の最後で)読み取ることができるので、最初に応答を取得しようとします。すべての finalrate を合計し、それらをカウントで割るために、グループを使用します。
現在のコードが機能する場合でも、コードには 2 つの問題があります。
1.-単一のクエリで Products を取得しようとしましたが、グループで products テーブルを使用できず、"orderby" で Response テーブルを使用できないため、取得できません。もう1つ、LINQでは1つのテーブルをグループ化する可能性しかありません。「グループ化、応答」を行うことは不可能です。LINQ でこの sql 文を取得できませんでした:
select prod.ProductID,prod.Commercial_Product_Name,prod.Manufacturer_Name,
prod.ProductImageUrl
from rev_product prod
inner join rev_response res on res.AtProductid=prod.ProductID
group by prod.ProductID,prod.Commercial_Product_Name,prod.Manufacturer_Name
,prod.ProductImageUrl
order by (sum(res.FinalRate)/count(res.AtProductid))
私はこれを試しました:
var gruposproductos = (from prod in ctx.Products
join res in ctx.Responses on prod.ProductID equals res.AtProductId
group prod by prod.ProductID into g
orderby (g.Sum(ra =>ra.FinalRate)/g.Count())
descending select g).Take(2);
しかし、私が言うように、「orderby (g.Sum...」はエラーになります。これは、「into g」が応答テーブルではなく製品テーブルをグループ化するためです。
これが、最終的なコードで、同じ LINQ 文で製品を取得できない理由です。
2.-この事実を受け入れると、問題は IGrouping を取得することですが、コードで 2 つの foreach を実行しないと反復できる応答のリストを取得できません。「リスト」オブジェクトの場合と同様に、ループを 1 つだけにしたかったのです。
それは本当にクールな方法ではありませんが、うまくいきます。さらに、2 番目のループでは 1 回だけ追加されるように制御する必要があります。
より良いコードはありますか?
var groupproducts = (from res in ctx.Responses
group res by res.AtProductId into g
orderby (g.Sum(ra =>ra.FinalRate)/g.Count())
descending select g).Take(2).ToList();
List<Product> theproducts = new List<Product>();
foreach (var groupresponse in groupproducts)
{
foreach (var response in groupresponse)
{
var producttemp= (from prod in ctx.Products
where prod.ProductID == response.AtProductId
select prod).First();
theproducts.Add(producttemp);
}
}
}
最終的な解決策(@Danielに感謝します)
var productsanonymtype = ctx.Products.Select(x => new
{
Product = x,
AverageRating = x.Responses.Count() == 0 ? 0 : x.Responses.Select(r => (double)r.FinalRate).Sum() / x.Responses.Count()
}).OrderByDescending(x => x.AverageRating);
List<Product> products = new List<Product>();
foreach (var prod in productsanonymtype)
{
products.Add(prod.Product);
}