Entity Framework中使用Inner Join关联导航属性的问题
解决方案
你的问题出在:直接通过Join关联后选择Blog,EF并不会自动将关联的Post聚合到Blog的Posts导航属性中,而且这种查询还会返回大量重复的Blog实例(每个关联的Post对应一个Blog副本)。以下是几种符合你需求的解决方案:
方法一:使用GroupJoin实现带Posts的Inner Join
通过GroupJoin先将Blog与对应的Post分组关联,再过滤掉没有关联Post的Blog(实现Inner Join的严格性),最后手动填充Posts属性:
var blogs = blogPostContext.Blogs .GroupJoin( blogPostContext.Posts, blog => blog.BlogId, post => post.BlogId, (blog, relatedPosts) => new { Blog = blog, Posts = relatedPosts }) .Where(result => result.Posts.Any()) // 过滤无关联Post的Blog,等价于Inner Join .Select(result => { result.Blog.Posts = result.Posts.ToList(); return result.Blog; }) .ToList();
方法二:先关联再内存分组
如果更习惯使用Join,可以先获取所有Blog-Post关联对,再在内存中分组并填充Posts属性:
// 先从数据库获取所有关联的Blog和Post对 var blogPostPairs = blogPostContext.Blogs .Join( blogPostContext.Posts, blog => blog.BlogId, post => post.BlogId, (blog, post) => new { Blog = blog, Post = post }) .ToList(); // 在内存中分组,将同一Blog的Post集合赋值给Posts属性 var blogs = blogPostPairs .GroupBy(pair => pair.Blog.BlogId) .Select(group => { var targetBlog = group.First().Blog; targetBlog.Posts = group.Select(pair => pair.Post).ToList(); return targetBlog; }) .ToList();
注意:这种方法会先将所有关联数据加载到内存,数据量大时可能影响性能,适合小数据集场景。
方法三:原生SQL结合Include
如果你愿意使用原生SQL,可以直接编写Inner Join语句,再通过Include让EF自动填充Posts导航属性——因为SQL本身是Inner Join,最终只会返回有关联Post的Blog:
var blogs = blogPostContext.Blogs .FromSqlRaw(@" SELECT b.*, p.PostId, p.Title, p.Content, p.BlogId FROM Blogs b INNER JOIN Posts p ON b.BlogId = p.BlogId ") .Include(b => b.Posts) .ToList();
需要确保你的实体关系配置正确,EF才能正确识别并映射关联的Post数据。
内容的提问来源于stack exchange,提问作者Akrem Hammami
相关产品推荐
相关产品推荐

