EF Core中Select()在ThenInclude()内不生效,如何映射TheaterDTO剔除冗余Screenings列表
解决方案
第一步:补充所需DTO定义
你只定义了TheaterDTO,还需要补充对应的ScreeningDTO和MovieDTO,避免直接返回实体类触发EF Core的关联修复逻辑导致冗余数据:
// 场次DTO public class ScreeningDTO { public DateTime Time { get; set; } public TheaterDTO Theater { get; set; } } // 电影DTO public class MovieDTO { public Guid Id { get; set; } public string Name { get; set; } public string Body { get; set; } public string Dir { get; set; } public string Pic { get; set; } public ICollection<ScreeningDTO> Screenings { get; set; } }
第二步:重写查询逻辑,使用投影查询
不要用Include加载实体导航属性,直接通过Select投影到DTO,EF Core会自动生成最简SQL,仅查询你需要的字段,不会拉取Theater下冗余的Screenings列表:
[HttpGet] [Route("{movieId}")] public MovieDTO GetMovieById(Guid movieId) { return _context.Movies .Where(m => m.Id == movieId) .Select(m => new MovieDTO { Id = m.Id, Name = m.Name, Body = m.Body, Dir = m.Dir, Pic = m.Pic, Screenings = m.Screenings.Select(s => new ScreeningDTO { Time = s.Time, Theater = new TheaterDTO { Name = s.Theater.Name, Address = s.Theater.Address } }).ToList() }) .FirstOrDefault(); }
可选简化方案:使用AutoMapper
如果不想每次手动写投影逻辑,可以引入AutoMapper,配置好实体和DTO的映射关系后,直接用ProjectTo方法即可实现相同效果:
// 需先注入IMapper实例 [HttpGet] [Route("{movieId}")] public MovieDTO GetMovieById(Guid movieId) { return _context.Movies .Where(m => m.Id == movieId) .ProjectTo<MovieDTO>(_mapper.ConfigurationProvider) .FirstOrDefault(); }
原问题原因说明
- 之前的接口返回类型为实体类
Movie,即使你不主动加载Theater的Screenings,EF Core的关联修复功能也会把已经加载的Screening对象自动关联到对应的Theater的Screenings集合中,导致冗余。 - 之前的查询逻辑错误:从Screenings表查询,且筛选条件写的是
m => movieId == m.Id,是用电影ID匹配场次ID,完全查不到正确数据。
内容的提问来源于stack exchange,提问作者user321
相关产品推荐
相关产品推荐

