LINQ查询SQLite时decimal类型Sum聚合报错,求解决方法
解决SQLite EF Core中decimal类型Sum聚合报错问题
问题背景
在使用EF Core查询SQLite数据库时,对decimal类型字段执行Sum聚合操作报错:
System.NotSupportedException: SQLite cannot apply aggregate operator 'Sum' on expressions of type 'decimal'. Convert the values to a supported type, or use LINQ to Objects to aggregate the results on the client side.
尝试显式转换decimal无效,需针对性解决。
解决方案
方案1:拉取数据到客户端内存后聚合(推荐,保留精度)
SQLite不支持数据库端对decimal的Sum操作,但LINQ to Objects(内存中)支持。先将符合条件的订单数据拉取到客户端,再执行分组聚合:
[HttpGet] public async Task<ActionResult<IEnumerable<ManagerAnalysis>>> GetManagerAnalysis() { if (_context.Orders == null) { return NotFound(); } // 先过滤近1个月的订单,仅选择需要的字段减少传输量 var recentOrders = await _context.Orders .Where(o => o.OrderTime > DateTime.Now.AddMonths(-1)) .Select(o => new { ManagerId = o.Manager.Id, ManagerName = o.Manager.Name, o.TotalPrice }) .ToListAsync(); // 拉取到客户端内存 // 内存中分组统计 var analysis = recentOrders .GroupBy(o => o.ManagerId) .Select(g => new ManagerAnalysis { ManagerName = g.First().ManagerName, OrderCount = g.Count(), OrdersPrice = g.Sum(p => p.TotalPrice) }); return Ok(analysis); }
优势:完全保留decimal的精度,避免浮点型精度损失;仅拉取必要字段,减少数据传输开销。
方案2:修改字段类型为double(适合精度要求低的场景)
将Order类的TotalPrice改为double类型,SQLite支持对double的Sum操作:
public class Order { public ulong Id { get; set; } public Manager Manager { get; set; } = new Manager(); public double TotalPrice { get; set; } // 替换为double public DateTime OrderTime { get; set; } } // 同时调整ManagerAnalysis对应属性类型(或转换) public class ManagerAnalysis { public string? ManagerName { get; set; } public int OrderCount { get; set; } public double OrdersPrice { get; set; } = 0; }
注意:double是浮点型,处理金额可能存在精度损失,仅适合对精度要求不高的业务场景。
方案3:使用原生SQL查询
直接编写SQL语句执行聚合,绕开EF Core的类型转换限制:
[HttpGet] public async Task<ActionResult<IEnumerable<ManagerAnalysis>>> GetManagerAnalysis() { if (_context.Orders == null) { return NotFound(); } var oneMonthAgo = DateTime.Now.AddMonths(-1); var analysis = await _context.Set<ManagerAnalysis>() .FromSqlRaw(@" SELECT m.Name AS ManagerName, COUNT(o.Id) AS OrderCount, SUM(o.TotalPrice) AS OrdersPrice FROM Orders o INNER JOIN Managers m ON o.ManagerId = m.Id WHERE o.OrderTime > {0} GROUP BY o.ManagerId", oneMonthAgo) .ToListAsync(); return Ok(analysis); }
说明:需确保ManagerAnalysis的属性名与SQL返回的列名一致,或通过[Column]特性映射;此方案在数据库端完成聚合,性能更优(大数据量场景)。
内容的提问来源于stack exchange,提问作者Mr. Luo
相关产品推荐
相关产品推荐

