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

如何用LINQ查询找出产品编号x订单量最高的城市?

如何将指定SQL转换为对应的LINQ查询?

没问题,我来帮你搞定这个LINQ查询的转换问题!先理清楚你的实体类结构和目标SQL的逻辑,然后一步步拆解实现。

你的实体类结构

public class Users 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Surname { get; set; } 
    public int CityId { get; set; } 
}

public class Order 
{ 
    public int Id { get; set; } 
    public int UserId { get; set; } 
}

public class OrderDetail 
{ 
    public int Id { get; set; } 
    public int OrderId { get; set; } 
    public int ProductId { get; set; } 
    public int Amount { get; set; } 
}

目标SQL语句

select * from (
    select u.CityId, sum(od.Amount), 
           ROW_NUMBER() over(order by sum(od.Amount) desc) as rn 
    from Order o 
    inner join OrderDetail od on o.Id = od.OrderId 
    inner join Users u on u.Id = o.UserId 
    where od.ProductId = x 
    group by u.CityId 
) where rn = 1;

对应的LINQ实现

这个SQL的核心逻辑是:关联三个表,过滤指定产品的订单详情,按城市分组计算总数量,然后给分组结果按总数量降序排号,最后取排号为1的城市(也就是总销量最高的城市)。

方式1:EF Core支持窗口函数的写法(推荐,数据库端执行)

这种写法会让数据库直接执行窗口函数,和原SQL的执行逻辑完全一致,性能更优:

// 替换x为你实际要传入的ProductId参数
int targetProductId = x;

var topCity = dbContext.Orders
    // 关联Order和OrderDetail
    .Join(dbContext.OrderDetails,
          order => order.Id,
          detail => detail.OrderId,
          (order, detail) => new { Order = order, Detail = detail })
    // 关联Users表
    .Join(dbContext.Users,
          combined => combined.Order.UserId,
          user => user.Id,
          (combined, user) => new { combined.Order, combined.Detail, User = user })
    // 过滤指定产品的订单详情
    .Where(item => item.Detail.ProductId == targetProductId)
    // 按城市ID分组,计算每个城市的总销量
    .GroupBy(item => item.User.CityId)
    .Select(group => new
    {
        CityId = group.Key,
        TotalAmount = group.Sum(item => item.Detail.Amount)
    })
    // 添加行号,按总销量降序排序
    .Select(result => new
    {
        result.CityId,
        result.TotalAmount,
        rn = EF.Functions.RowNumber().Over(orderBy: r => r.TotalAmount descending)
    })
    // 筛选行号为1的记录
    .Where(r => r.rn == 1)
    .FirstOrDefault();

方式2:内存中处理的写法(适合数据已加载到内存的场景)

如果你的数据已经被加载到内存中(比如用ToList()提前获取了所有数据),可以用这种基于索引的方式模拟行号:

int targetProductId = x;

var topCity = (from order in dbContext.Orders.AsEnumerable()
               join detail in dbContext.OrderDetails.AsEnumerable() on order.Id equals detail.OrderId
               join user in dbContext.Users.AsEnumerable() on order.UserId equals user.Id
               where detail.ProductId == targetProductId
               group detail by user.CityId into cityGroup
               select new
               {
                   CityId = cityGroup.Key,
                   TotalAmount = cityGroup.Sum(d => d.Amount)
               })
               // 先按总销量降序排序
               .OrderByDescending(item => item.TotalAmount)
               // 给排序后的结果添加行号(索引从0开始,所以+1)
               .Select((item, index) => new
               {
                   item.CityId,
                   item.TotalAmount,
                   rn = index + 1
               })
               .Where(item => item.rn == 1)
               .FirstOrDefault();

说明

  • 推荐使用第一种方式,因为它会将所有逻辑下推到数据库执行,减少内存占用和数据传输量。
  • 两种写法最终都会得到你想要的结果:总销量最高的城市ID及其对应的总销量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:00:07