我对由linq产生的对象IGrouping有疑问,我使用" group by"句。
我在数据库中有两个表,产品和响应它们之间的关系是1到*。在Responses表中,我们有一个名为FinalRate的列,它是产品的速率。产品可以有n个回复或率。
我希望通过FinalRate的总和除以完成的费率数来获得产品订单。也就是说,按平均比率从高到低的顺序排序。
因为它可以在代码中读到(在问题的最后),我试着先得到答案。为了总结所有的最终结果并将它们除以计数,我使用了一个组。
代码存在2个问题,即使当前代码有效:
1.-我试图在单个查询中获取产品,但这是不可能的,因为我不能在组中使用products表,然后使用" orderby"中的Response表。还有一件事LINQ只允许你对一个表进行分组,那么就不可能有" group prod,response"。 我无法在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);
但正如我所说,&#34; orderby(g.Sum ...&#34;给出错误,因为&#34;进入g&#34;对产品表进行分组,而不是响应表。< / p>
所以这就是为什么在我的最终代码中我不能用相同的LINQ句子获得产品。
2.-一旦接受了这个事实,问题是我得到了一个IGrouping,但是我没有获得一个响应列表,我可以迭代而不用代码中的两个foreach。我只想要一个循环,就像你有一个&#34; List&#34;对象
这不是一个很酷的方法,但它有效。而且,我必须控制在第二个循环中只增加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);
}
答案 0 :(得分:1)
试试这个:
products.Select(x => new
{
Product = x,
AverageRating = x.Responses.Sum(x => x.FinalRate) /
x.Responses.Count()
});
我正在使用的Sum
重载未在所有提供程序中实现。如果这对您来说是个问题,您可以使用此备用版本:
products.Select(x => new
{
Product = x,
AverageRating = x.Responses.Select(x => x.FinalRate)
.Sum() /
x.Responses.Count()
});
如果从产品到其响应没有导航属性,您应该首先尝试修复它。如果你不能,你可以使用这个版本:
products.Join(responses, x => x.Id, x => x.ProductId,
(p, r) => new { Product = p, Response = r })
.GroupBy(x => x.Product)
.Select(g => new { Product = g.Key,
AverageRating = g.Select(x => x.Response.FinalRate)
.Sum() /
g.Count()
});
假设FinalRate
是int
,两种方法都会用int计算平均评级,即没有4.5评级。并且没有四舍五入,即实际平均等级为4.9将导致4.您可以通过将该分部的一个操作数强制转换为double
来解决此问题。
另一个问题是到目前为止没有评级的情况。在这种情况下,上面的代码将导致异常。如果这对您来说是个问题,您可以将计算更改为:
AverageRating = g.Count() == 0
? 0
: g.Select(x => (double)x.Response.FinalRate).Sum() / g.Count()
答案 1 :(得分:1)
ctx.Products.GroupBy(x => new {
ProductId = x.ProductId,
FinalRate = x.Responses.Sum(y => y.FinalRate),
CountProductId = x.Responses.Count
})
.OrderBy(x => x.Key.FinalRate / x.Key.CountProductId);
这里有投影......
ctx.Products.Select(x => new {
ProductID = x.ProductID,
Commercial_Product_Name = x.Commercial_Product_Name,
Manufacturer_Name = x.Manufacturer_Name,
ProductImageUrl = x.ProductImageUrl,
FinalRate = x.Responses.Sum(y => y.FinalRate),
CountProductId = x.Responses.Count
})
.GroupBy(x => new {
ProductId = x.ProductId,
FinalRate = x.FinalRate,
CountProductId = x.CountProductId
})
.OrderBy(x => x.Key.FinalRate / x.Key.CountProductId);