EF Core 8.0.6中如何高效实现订单表按订单号去重后关联客户表并映射为DTO
EF Core 8.0.6中如何高效实现订单表按订单号去重后关联客户表并映射为DTO
嗨,我来给你几个高效又简洁的方案,都是适配EF Core 8.0.6的,完美匹配你的需求——按订单号去重后关联客户表,最终映射成CustomerOrder DTO:
方案一:用DistinctBy实现极简去重(推荐优先用)
EF Core 5及以上版本提供了DistinctBy方法,可以直接指定去重的字段,代码最简洁,生成的SQL效率也很高:
var customerOrders = await _context.Orders // 按订单号去重,每个订单号只保留一条记录 .DistinctBy(o => o.Order_Number) // 关联客户表,关联条件是双方的Customer_Key相等 .Join( _context.Customers, order => order.Customer_Key, customer => customer.Customer_Key, // 映射到你的DTO (order, customer) => new CustomerOrder { OrderNumber = order.Order_Number, CustomerNumber = customer.Customer_No, CustomerName = $"{customer.First_Name} {customer.Last_Name}", Address = customer.Address, City = customer.City, State = customer.State, ZipCode = customer.Zip_Code, Email = customer.eMail, Phone = customer.Phone // 补充你需要的其他DTO字段 }) .ToListAsync();
这个方案的优势是代码直观,EF Core会帮你生成最优的去重SQL,不需要自己写复杂的分组逻辑,适合只需要简单去重的场景。
方案二:用窗口函数精准控制去重规则(适合有排序需求的场景)
如果你的订单表中,同一个订单号对应的多条记录有先后顺序(比如你想取最新创建的那条),EF Core 8.0对窗口函数的支持非常完善,可以用RowNumber来实现精准去重:
var customerOrders = await _context.Orders // 先给每个订单号的记录分配行号,按你需要的规则排序(比如这里用Order_Number,你可以换成创建时间等字段) .Select(o => new { o.Order_Number, o.Customer_Key, RowNum = EF.Functions.RowNumber().Over( partitionBy: o.Order_Number, orderBy: o.Order_Number) // 这里可以改成 orderBy: o.CreationTime descending 来取最新记录 }) // 只保留每个订单号的第一条记录 .Where(r => r.RowNum == 1) // 关联客户表并映射DTO .Join( _context.Customers, r => r.Customer_Key, c => c.Customer_Key, (r, c) => new CustomerOrder { OrderNumber = r.Order_Number, CustomerNumber = c.Customer_No, CustomerName = $"{c.First_Name} {c.Last_Name}", Address = c.Address, City = c.City, State = c.State, ZipCode = c.Zip_Code, Email = c.eMail, Phone = c.Phone }) .ToListAsync();
这种方案适合需要精准控制去重逻辑的场景,比如必须取每个订单号的最新/最早记录,生成的SQL会用窗口函数,性能也很出色。
方案三:用GroupBy分组去重
如果你习惯用分组的方式处理,也可以通过GroupBy按订单号分组,再取每组的第一条记录:
var customerOrders = await _context.Orders // 按订单号分组 .GroupBy(o => o.Order_Number) // 取每组的第一条记录(如果需要排序,可以在GroupBy后加OrderBy再取First) .Select(g => g.First()) // 关联客户表并映射DTO .Join( _context.Customers, order => order.Customer_Key, customer => customer.Customer_Key, (order, customer) => new CustomerOrder { OrderNumber = order.Order_Number, CustomerNumber = customer.Customer_No, CustomerName = $"{customer.First_Name} {customer.Last_Name}", Address = customer.Address, City = customer.City, State = customer.State, ZipCode = customer.Zip_Code, Email = customer.eMail, Phone = customer.Phone }) .ToListAsync();
这个方案和DistinctBy的效果类似,但如果需要对分组后的记录做额外处理(比如统计每组的数量),GroupBy会更灵活。
性能优化小提示
- 确保
Orders表的Order_Number字段和Customer_Key字段有索引,Customers表的Customer_Key字段(主键应该已经有索引了)也确保是索引字段,这样去重和关联的速度会大幅提升。 - 尽量只选择DTO需要的字段,不要查询整个实体,减少数据库返回的数据量,提升查询效率。
备注:内容来源于stack exchange,提问作者Turner




