C# 具有多个GroupBy需求的多连接LINQ扩展方法

C# 具有多个GroupBy需求的多连接LINQ扩展方法,c#,entity-framework,linq,C#,Entity Framework,Linq,作为学习EF的练习,我有以下4个表Person 1toM,通过OrderProducts订购M2M,产品(性别是一个Enum): 我致力于LINQ扩展方法,希望我也能在这里开发一些最佳实践。我现在无法确定如何按ProductName进行分组,并将quaty*Price汇总为按产品列出的总数: var prodsalesbygender = context.Orders .GroupBy(o => new { Gender = o.Person.Ge

作为学习
EF
的练习,我有以下4个表
Person 1toM
,通过OrderProducts订购M2M,
产品(性别是一个
Enum
):

我致力于LINQ扩展方法,希望我也能在这里开发一些最佳实践。我现在无法确定如何按
ProductName
进行分组,并将
quaty*Price
汇总为按产品列出的总数:

var prodsalesbygender = context.Orders
    .GroupBy(o => new 
    {
            Gender = o.Person.Gender
    })
    .Select(g => new
    {
        ProductName = g.Select(o => o.OrderProducts.Select(op => op.Product.Name)),
        Qty = g.Select(o => o.OrderProducts.Select(op => op.Qty)),
        Price = g.Select(o => o.OrderProducts.Select(op => op.Product.Price))
    }
);

我已尝试将
.GroupBy(g=>g.ProductName)
添加到末尾,但出现错误“用于调用'GroupBy'方法的键选择器类型在基础存储提供程序中不可比较。”

我想你就快到了。。 试试这个:

       var prodsalesbygender = context.Orders
                                      .GroupBy(o => new
                                      {
                                          Gender = o.Person.Gender
                                      })
                                      .Select(g => new
                                      {
                                          Gender = g.Key,
                                          Products = g.Select(o => o.OrderProducts
                                                                    .GroupBy(op => op.Product)
                                                                    .Select(op => new
                                                                    {
                                                                        ProductName = op.Key.Name,
                                                                        Qty = op.Sum(op2 => op2.Qty),
                                                                        Price = op.Select(x => x.Product.Price)
                                                                                  .First(),
                                                                    })
                                                                    .Select(x => new
                                                                    {
                                                                        ProducName = x.ProductName,
                                                                        Qty = x.Qty,
                                                                        Price = x.Price,
                                                                        TotalPrice = x.Qty * x.Price
                                                                    }))
                                      });
简而言之,你只需要更多的投影。在我建议的解决方案中,首先按性别分组。下一步是直接预测性别和“产品列表”(是的,难以绕过的部分是
OrderProducts
)。在
产品中
我们根据产品名称对其进行分组,然后获取总数量(
数量
),并设置
价格
——假设相同产品的价格是恒定的。下一步是设置
TotalPrice
Qty*Price
东西

另外,我完全知道这个问题有很多不足之处。也许LINQ专家可以在这方面提供更好的帮助

它将生成一个类似以下内容的类:

  {
    Gender Gender
    IEnumerable<{ ProductName, Qty, Price, TotalPrice }> Products
  }
{
性别
可数产品
}
是的,匿名类型就到此为止


尽管如此,我还是被否决票难住了,因为该问题包含有问题的模型和OP提供的尝试。

最后,这是我的解决方案,产生的结果完全符合要求

var prodsalesbygender = context.OrderProducts
    .GroupBy(op => new
    {
        Gender = op.Order.Person.Gender
    })
    .Select(g => new
    {
        Gender = g.Key.Gender,
        Products = g.GroupBy(op => op.Product)
        .Select(a => new
        {
            ProductName = a.Key.Name,
            Total = a.Sum(op => op.Qty * op.Product.Price)
        })
        .OrderBy(a => a.ProductName)
    });

foreach (var x in prodsalesbygender)
{
    Console.WriteLine(x.Gender);
    foreach (var a in x.Products)
        Console.WriteLine($"\t{a.ProductName} - {a.Total}");
}

感谢@Bagus Tesa

大家好,欢迎来到Stack Overflow!这是一个有趣的问题,但我认为你应该把它编辑得更短。您是否可以大幅减少代码块,以获得最小数量的代码来重现和表示您的问题?这样,更多的人会阅读问题,你会更快地得到答案。还有,你试过什么,但没有用?简单地提及那些没有起作用的东西也会改善这个问题。谢谢,祝你好运!谢谢Max-我已经删除了一些不相关的属性并接受了你的建议。只是在这里学习,不用担心!谢谢你澄清这个问题。我不是LINQ专家,但你的问题越短、可读性越强,LINQ专家就越有可能阅读并回答它。祝你好运非常感谢你的帮助。我运行了您的查询,当它计算总数时,它在订单级别按记录进行计算,但不聚合到产品级别。越来越近。。。我很欣赏你对否决票的评论——作为一个努力学习并最终做出贡献的相对新人,他们有点令人沮丧。我会及时了解的。嗨@deldridg,我理解你的担忧,但是,
订单产品
只有
数量
,没有价格。。因此,我们需要从
产品
本身获取价格。嗨@Bagus Tesa-这就是我试图解决的问题。正如你所说的,我试图返回你描述的类。我们的新查询为每个订单返回一个IEnumerable(总共100个),而不是一个产品列表(总共10个),如果这有意义的话!啊,我明白你的问题了,我们不应该从订单上解决这个问题。。因为我们是根据性别和总销售额汇总
产品
,对吗?编辑,嗯,我认为,从产品是不可行的。嗯-听起来正确。我在没有性别条款的情况下一直在讨论这个问题,而且似乎有点接近了。不确定我是否可以在这里发布“部分解决方案”。。。
  {
    Gender Gender
    IEnumerable<{ ProductName, Qty, Price, TotalPrice }> Products
  }
var prodsalesbygender = context.OrderProducts
    .GroupBy(op => new
    {
        Gender = op.Order.Person.Gender
    })
    .Select(g => new
    {
        Gender = g.Key.Gender,
        Products = g.GroupBy(op => op.Product)
        .Select(a => new
        {
            ProductName = a.Key.Name,
            Total = a.Sum(op => op.Qty * op.Product.Price)
        })
        .OrderBy(a => a.ProductName)
    });

foreach (var x in prodsalesbygender)
{
    Console.WriteLine(x.Gender);
    foreach (var a in x.Products)
        Console.WriteLine($"\t{a.ProductName} - {a.Total}");
}