如何在dotnet core Entity Framework中对多个表的数据进行GroupBy操作?

问题描述 投票:3回答:1

我正在构建一些市场的web应用,比方说像e-bay这样的东西。典型的场景是:用户提出一个或多个物品的报价,这些物品是某种类型的。

用户出价,其中包括一个或多个项目,这些项目是特定的类型,然后其他用户对该报价进行竞价。

这里是简化的图。

diagram

在SQL Fiddle (此处)你可以看到CREATE TABLE和INSERT INTO两个语句。

样本数据。有两个报价。其中一个报价(Id 1)包含一件商品,类型为 "手表"。另一个报价(Id 2),其中有一件物品是 "耳机"。两个报价都有出价。在手表上,有两个人出价,一个人出价100美元,另一个人出价120美元。在耳机上,有50美元和80美元的出价。

我想实现的是每一种类型的平均出价。在这个样本中,这意味着我想让手表的平均出价为110美元,耳机的平均出价为65美元。为了达到这个目的,使用T-SQL,我会写这样的查询。

SELECT t.name,
       avg(amount)
FROM bid b
LEFT JOIN offer o ON b.OfferId = o.id
LEFT JOIN offeritem oi ON o.id = oi.OfferId
LEFT JOIN itemType t ON oi.itemtypeid = t.Id
GROUP BY t.name

所以,我的问题是,如何在dotnet core 3. 0 EntityFramework中实现这个目标?

使用GroupBy,像这样。

_context.Bids
    .Include(b => b.Offer)
        .ThenInclude(o => o.OfferItems)
            .ThenInclude(os => os.ItemType)
    .GroupBy(b => b.Offer.OfferItems.First().ItemType.Name);

就会产生异常

客户端不支持GroupBy。

. 当我尝试使用投影,像这样。

_context.Bids
    .Include(b => b.Offer)
        .ThenInclude(o => o.OfferItems)
            .ThenInclude(os => os.ItemType)
    .GroupBy(b => b.Offer.OfferItems.First().ItemType.Name)
    .Select(g => new
    {
        Key = g,
        Value = g.Average(b => b.Amount)
    });

我又得到异常:

处理LINQ......失败。这可能表明EF Core的一个错误或限制。

EDIT:

这种方法

_context.Bids
    .Include(b => b.Offer)
        .ThenInclude(o => o.OfferItems)
            .ThenInclude(os => os.ItemType)
    .GroupBy(b => new { b.Offer.OfferItems.First().ItemType.Name}, b => b.Amount)
    .Select(g => new
    {
        Key = g.Key.Code,
        Value = g.Average()
    });

也抛出了一个异常,但这次。

不能在GROUP BY子句的group by list表达式中使用集合或子查询。

...

那么,有没有一种方法可以对数据进行分组(得到简单的Average),或者我应该再做一个查询,然后自己遍历集合并进行计算?这肯定会降低性能(我希望我可以做服务器分组,但正如你所看到的,我遇到了上述问题)。有什么想法吗?先谢谢你了。

c# .net-core entity-framework-core
1个回答
1
投票

在你的案例中,很难隐藏分组中的子查询。

你可以试试这样的方式

var joined =
    context.Bid
        .SelectMany(x =>
            x.Offer.OfferItem
                .Select(y => new
                {
                    Amount = x.Amount,
                    Name = y.ItemType.Name
                })
                .Take(1));

var grouped = from i in joined
    group i by i.Name into groups
    select new
    {
        Key = groups.Key,
        Amount = groups.Average(x => x.Amount)
    };

它给我一个查询

SELECT [t].[Name] AS [Key], AVG([t].[Amount]) AS [Amount]
  FROM [Bid] AS [b]
  INNER JOIN [Offer] AS [o] ON [b].[OfferId] = [o].[Id]
  CROSS APPLY (
      SELECT TOP(1) [b].[Amount], [i].[Name], [o0].[Id], [i].[Id] AS [Id0], [o0].[OfferId]
      FROM [OfferItem] AS [o0]
      INNER JOIN [ItemType] AS [i] ON [o0].[ItemTypeId] = [i].[Id]
      WHERE [o].[Id] = [o0].[OfferId]
  ) AS [t]
  GROUP BY [t].[Name]
© www.soinside.com 2019 - 2024. All rights reserved.