如何阻止Entity Framework Core 6生成额外的左连接?
问题:EF Core 6关联查询时出现额外左连接的解决方法
我用Entity Framework Core 6结合SQLite做查询,手动对Route(父表)和Stop(子表)做了内连接,但在select子句里用r.Stops构建DTO的Stops属性时,EF Core自动多加了一个左连接,怎么重构查询解决这个问题?
实体类定义
Route(父实体)
[Table("Route")] public partial class Route { public Route() { Stops = new HashSet<Stop>(); } [Key] [Column("id")] public int Id { get; set; } /// Some properties [InverseProperty("Route")] public virtual ICollection<Stop> Stops { get; set; } }
Stop(子实体)
[Table("Stop")] public partial class Stop { [Key] [Column("id")] public int Id { get; set; } /// Some properties [Column("RouteId")] public int? RouteId { get; set; } [ForeignKey("RouteId")] [InverseProperty("Stops")] public virtual Route Route { get; set; } }
原查询代码及问题
原查询手动做了内连接,但生成的SQL多了一次左连接:
var routeToSend = await (from r in context.Routes join s in context.Stops on r.Id equals s.RouteId where r.SendToServer == true select new RouteDto { ..., Stops = r.Stops.Select(s => new StopClassDto { ... }).ToList() } ).ToListAsync();
生成的SQL:
SELECT some columns FROM "Route" AS "r" INNER JOIN "Stop" AS "s" ON "r"."id" = "s"."RouteId" LEFT JOIN "Stop" AS "s0" ON "r"."id" = "s0"."RouteId" WHERE "r"."sendToServer" ORDER BY "r"."id", "s"."id"
问题根源:r.Stops是导航属性,EF Core会将其视为独立的关联查询,因此额外生成左连接,和手动的内连接重复。
重构方案
方案1:利用导航属性替代手动内连接(推荐)
直接通过导航属性的过滤实现内连接效果,同时投影DTO,EF会自动生成单次连接:
var routeToSend = await context.Routes .Where(r => r.SendToServer == true && r.Stops.Any()) // 仅保留关联了Stop的Route,等价于内连接 .Select(r => new RouteDto { // 映射Route的属性 Id = r.Id, // 其他Route属性... Stops = r.Stops.Select(s => new StopClassDto { // 映射Stop的属性 Id = s.Id, // 其他Stop属性... }).ToList() }) .ToListAsync();
方案2:手动join后分组投影
如果必须保留手动join的写法,通过分组避免重复访问导航属性:
var routeToSend = await (from r in context.Routes join s in context.Stops on r.Id equals s.RouteId where r.SendToServer == true // 按Route分组,聚合对应的Stop集合 group s by r into routeGroup select new RouteDto { // 从分组Key中取Route属性 Id = routeGroup.Key.Id, // 其他Route属性... // 从分组集合中取Stop数据 Stops = routeGroup.Select(s => new StopClassDto { Id = s.Id, // 其他Stop属性... }).ToList() }) .ToListAsync();
内容的提问来源于stack exchange,提问作者bowend01
相关产品推荐
相关产品推荐

