LINQ:如何获得一组具有相关表的表排序



我对linq中使用"groupby"语句产生的对象IGrouping有疑问。

我在数据库中有两个表,Products和Responses,它们之间有1到*的关系。在响应表中,我们有一个名为FinalRate的列,它是产品的速率。产品可以有n个响应或速率。

我想用FinalRate的总和除以完成的费率的数量来获得产品订单。也就是说,按平均顺序从高到低打分。

由于它可以在代码中阅读(在问题的末尾),我试图首先得到答案。为了将所有的最终结果求和并除以计数,我使用了一组。

代码有2个问题,即使当前代码有效:

1.-我试图在一个查询中获得Products,但这是不可能的,因为我不能使用组中的Products表,然后使用"orderby"中的Response表。还有一件事,LINQ只给你分组一张表的可能性,不可能有"分组刺激、响应"。我在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"将Product表分组,而不是Response表

这就是为什么在我的最终代码中,我没有在同一个LINQ语句中得到产品。

2.-一旦接受了这个事实,问题是我得到了一个IGrouping,但我没有得到一个响应列表,我可以在不执行代码中的两个foreach的情况下迭代这些响应。我只想要一个循环,就像你有一个"List"对象时那样。

这不是一个很酷的方法,但它确实有效。此外,我必须控制在第二个循环中只增加了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);
        }
     }
  }

最终解决方案(thx很多@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);
                }

试试这个:

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()
                         });

假设FinalRateint,两种方法都将用int计算平均评级,即不会有4.5的评级。并且不会四舍五入,即4.9的实际平均评级将得到4。可以通过将除法的一个操作数强制转换为double来解决此问题。

另一个问题是目前还没有评级。在这种情况下,上面的代码将导致一个异常。如果这对你来说是个问题,你可以将计算更改为:

AverageRating = g.Count() == 0
                ? 0
                : g.Select(x => (double)x.Response.FinalRate).Sum() / g.Count()
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);

相关内容

  • 没有找到相关文章

最新更新