You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在EF Core中用LINQ查询指定年龄段的畅销图书

错误原因

两种写法的核心问题都是聚合逻辑的位置不对:

  • 第一种写法未做分组就尝试调用Sum,此时的oi是单条订单项对象,不是同一图书对应的所有订单项集合,无法正确聚合;多表JOIN后一本图书对应多条订单项、订单记录,会产生大量重复行,仅用Distinct()去重解决不了销量统计错误的问题。
  • 第二种写法分组前只select b,直接丢失了关联的订单项销量数据、用户年龄匹配的关联记录,分组后自然无法获取到需要求和的Amount字段。
正确实现代码

下面的写法完全对齐你手写的MySQL查询逻辑,EF Core可以直接翻译为正确的SQL语句,无客户端评估:

var targetMinAge = 17;
var targetMaxAge = 27;
var result = (from b in _context.Book
              join oi in _context.OrderItem on b.Id equals oi.Fk_BookId
              join o in _context.Order on oi.Fk_OrderId equals o.Id
              join u in _context.Users on o.UserID equals u.Id
              let userAge = EF.Functions.DateDiffYear(u.DateofBirth, DateTime.Now)
              where userAge >= targetMinAge && userAge <= targetMaxAge
              select new 
              {
                  BookData = b,
                  SingleItemSale = oi.Amount
              })
              .GroupBy(x => x.BookData.Id)
              .Select(group => 
              {
                  var bookInfo = group.First().BookData;
                  return new BookForRecomendVM
                  {
                      Id = bookInfo.Id,
                      Title = bookInfo.Title,
                      Pages = bookInfo.Pages,
                      Format = bookInfo.Format,
                      LongDescription = bookInfo.LongDescription,
                      ShortDescription = bookInfo.ShortDescription,
                      Amount = bookInfo.Amount,
                      Price = bookInfo.Price,
                      ImageUrl = bookInfo.ImageUrl,
                      IsFavor = bookInfo.IsFavor,
                      ReleaseDate = bookInfo.ReleaseDate,
                      PublisherName = bookInfo.Publisher?.Name,
                      NumOfSales = group.Sum(item => item.SingleItemSale)
                  };
              })
              .OrderByDescending(vm => vm.NumOfSales)
              .ToList();
补充说明
  • 代码中用let关键字抽离年龄计算逻辑,避免重复调用日期函数,EF Core生成的SQL会和你手写的TIMESTAMPDIFF逻辑完全一致,执行效率更高。
  • 该写法兼容EF Core 3.1及以上所有版本,不会出现分组后无法翻译、导航属性加载失败的问题。
  • 如果需要额外过滤有效订单(比如排除已取消、待支付的订单),直接在where子句中增加订单状态的判断条件即可。
  • 注意:代码中PublisherName字段取值用的是bookInfo.Publisher?.Name,如果你的Publisher实体中出版社名称属性不是Name,请替换为你实际定义的属性名。

内容的提问来源于stack exchange,提问作者Lys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:54:31