我有以下型号:
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Description { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
我有一个IQueryable,如:
var results = Blog.Include(x => x.Posts);
在我想过滤Post类的属性之前,一切工作都很好。我需要这样的东西:
var filteredResults = results.Where(x => x.Posts.Where(y => y.Description == "Test"));
如果我将Any()附加到第二个.Where()上,则此方法有效。但这不是正确的,因为我只想返回匹配的帖子,而不是全部。 有关如何解决此问题的任何建议?
答案 0 :(得分:1)
实体不这样过滤。 Blog实体将并且应该引用与其关联的 ALL 帖子。 EF可以将全局过滤器应用于数据,以适应诸如软删除(IsActive)或租户(ClientId)方案之类的事情,但不能像这样过滤子级。
这是一个视图/消费者关注点,而不是域关注点,因此您应该使用Projection返回所需的数据来分离这些关注点:
string postFilter = "Test";
var filteredResults = context.Blogs
.Where(x => x.Posts.Any(p => p.Description == postFilter))
.Select(x => new BlogViewModel
{
BlogId = x.BlogId,
Title = x.Title,
FilteredPosts = x.Posts.Where(p => p.Description == postFilter)
.Select(p => new PostViewModel
{
PostId = p.PostId,
Description = p.Description,
Text = p.Text,
// ...
{).ToList()
}).ToList();
答案 1 :(得分:0)
您可以自下而上地解决这个问题。
var blogIds = Posts.Where(x => x.Description == "Test").Select(x => x.BlogId);
var result = Blog.Where(x => blogIds.Contains(x.Id))
请注意,您可能想这样做:
x => x.Description.Contains("Test")
代替:
x => x.Description == "Test"
第一次查询
尽管如此,您仍然必须将相应的帖子映射到每个博客
更新
史蒂夫的答案是正确的。我只是补充说,它可能会转换为许多嵌套的选择查询。您可以在SQL Server事件探查器中或Visual Sudio的输出窗口中检查输出。因此,这里包括映射在内的所有内容:
var posts = Posts.Where(x => x.Description == "test").ToList();
var blogIds = posts.Select(x => x.BlogId).ToList();
var blogs = Blog.Where(x => blogIds.Contains(x.Id)).ToList();
foreach(var blog in blogs)
blog.Posts = posts.Where(x => x.BlogId == x.Id).ToList()