EF Core 3.1中如何将SQL查询结果映射到[NotMapped]属性
解决EF Core 3.1中[NotMapped]属性映射自定义SQL返回列的问题
核心问题原因
你之前的方案触发重复关联查询,本质是因为直接用实体类执行FromSqlRaw时,EF Core会默认校验实体的映射关系,甚至可能自动加载关联实体(比如懒加载),忽略了你自定义SQL里已经完成的关联操作。要解决这个问题,需要绕开EF对实体关联的自动处理,直接将SQL返回的结果映射到实体的[NotMapped]属性上。
方法一:用dynamic中转映射(快速实现)
利用EF Core 3.1的Database.SqlQuery<dynamic>直接读取SQL原始结果,再手动映射到实体的[NotMapped]属性,完全避免EF的自动关联逻辑。
// 你的自定义SQL(已包含关联查询) var sqlString = @"SELECT o.Id, o.OrderNumber, c.Name AS CustomerName, b.Name AS BuyerName FROM Orders o JOIN Customers c ON o.CustomerId = c.Id JOIN Buyers b ON o.BuyerId = b.Id"; // 直接执行SQL并映射到实体 var orders = context.Database.SqlQuery<dynamic>(sqlString) .Select(x => new Order { Id = x.Id, OrderNumber = x.OrderNumber, CustomerName = x.CustomerName, // 赋值给NotMapped属性 BuyerName = x.BuyerName // 赋值给NotMapped属性 }) .ToList();
注意:需要确保引用了
Microsoft.EntityFrameworkCore.Relational包,SqlQuery方法才会生效。
方法二:用DTO做载体(类型更安全)
创建一个和SQL返回列完全匹配的DTO类(无需标记[NotMapped]),先用FromSqlRaw查询到DTO,再转换为目标实体,避免dynamic的类型风险。
// 定义与SQL返回列匹配的DTO public class OrderDto { public int Id { get; set; } public string OrderNumber { get; set; } public string CustomerName { get; set; } public string BuyerName { get; set; } } // 查询并转换 var sqlString = @"SELECT o.Id, o.OrderNumber, c.Name AS CustomerName, b.Name AS BuyerName FROM Orders o JOIN Customers c ON o.CustomerId = c.Id JOIN Buyers b ON o.BuyerId = b.Id"; var orderDtos = context.Set<OrderDto>().FromSqlRaw(sqlString).ToList(); var orders = orderDtos.Select(dto => new Order { Id = dto.Id, OrderNumber = dto.OrderNumber, CustomerName = dto.CustomerName, BuyerName = dto.BuyerName }).ToList();
这个方法的优势是编译期就能检查字段匹配问题,适合复杂查询场景。
关键注意事项
- 不要直接用
context.Orders.FromSqlRaw(sqlString)查询实体,EF会尝试补全实体的关联映射,导致重复执行关联SQL。 - 两种方法都完全依赖你自定义的SQL逻辑,EF不会额外添加任何关联查询,确保性能最优。
内容的提问来源于stack exchange,提问作者Răzvan Puștea
相关产品推荐
相关产品推荐

