【问题标题】:Group by and sum column using Entity Framework使用实体框架对列进行分组和求和
【发布时间】:2021-11-02 14:35:52
【问题描述】:

我有三个实体,第一个是Product

public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public DateTime CratedDate { get; set; } = DateTime.Now;
    public ApplicationUser ApplicationUser { get; set; }
    public string ApplicationUserId { get; set; }
    public ProductCategory ProductCategory { get; set; }
    public Guid ProductCategoryId { get; set; }
    public string ProductType { get; set; }
}

第二个实体是Users:

public class ApplicationUser : IdentityUser
{
    public string DisplayName { get; set; }
    public decimal Balance { get; set; }
    public virtual IEnumerable<Product> Products { get; set; }
    public virtual IEnumerable<Order> Orders { get; set; }
}

第三个实体是Order

public class Order
{
    public Guid Id { get; set; }
    public Product Product { get; set; }
    public Guid ProductId { get; set; }
    public ApplicationUser User { get; set; }
    public string UserId { get; set; }
    public DateTime OrderDate { get; set; }
}

我尝试使用以下代码获取订单并按用户分组并获取产品总价:

var orders = _db.Orders.GroupBy(x => x.User.UserName)
                       .Select(x => new
                                    {
                                        userName = x.Key, 
                                        toolsCount = x.Count(), 
                                        totalPrice = x.Sum(s => s.Product.Price)
                                    })
                       .ToList();

但我收到此错误:

System.InvalidOperationException:LINQ 表达式 'GroupByShaperExpression:

KeySelector:a.UserName,
ElementSelector:EntityShaperExpression:
实体类型:订单
值缓冲区表达式:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: 假

.Sum(s => s.Product.Price)' 无法翻译。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。请参阅https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。 )

【问题讨论】:

  • 出于好奇,如果你:.GroupBy(x =&gt;x.User.UserName, x =&gt; x.Product.Price) 并将totalPrice = x.Sum(s=&gt;s.Product.Price) 交换为totalPrice = x.Sum() 是否有效?
  • 干得好,谢谢

标签: c# entity-framework asp.net-core


【解决方案1】:

我建议您使用 GroupBy 的重载,它采用 lambda 来创建分组的输出对象:

.GroupBy(x =>x.User.UserName, x => x.Product.Price) 

然后改变

totalPrice = x.Sum(s=>s.Product.Price)

totalPrice = x.Sum()

因为 X 现在是价格(数字)列表,而不是订单实体列表


在 EF 进行连接以从 order->user->username 获取密钥时,它也可以知道您想要从 order->product->price 获取并为此进行连接,最终只产生一个用户名和价格列表..

..稍后在选择部分,它会找出如何处理列表:按名称分组(它知道该部分)并分别计算和汇总价格。这很容易转化为 SQL;它正在努力解决的问题是,拉取了订单和相关用户的列表,并建立了一个按用户名对订单进行分组的查询,然后要求它从订单到产品以获取价格,但由于产品不是最初是隐式或显式包含的,现在开始引入相关的必要数据的步骤有点晚

总而言之,我希望这种修改后的表单可以让 EF 更快地计算出您想要的连接,最终会得到如下查询:

  SELECT u.Name AS ..., COALESCE(SUM(p.Price), 0.0) AS ...
  FROM Orders AS o
  INNER JOIN Products AS p ON o.ProductId = p.ProductId
  INNER JOIN Users AS u ON o.UserId = u.UserId
  GROUP BY u.Name

没有“抬头”,它不知道要加入产品..

【讨论】:

  • @adelibrahim:如果这个答案帮助你解决了你的问题,那么请accept this answer。这将表达您对花费自己的时间帮助您的人们的感激之情。
  • 不错!我现在看到使用 LINQ 和这个挑剔的 Entity Framework 核心让我忘记探索其他支持的重载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-25
  • 2015-05-17
相关资源
最近更新 更多