如何用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
相关产品推荐
相关产品推荐

