Entity Framework 中的条件包含 ()
Conditional Include() in Entity Framework
我看过一些类似问题的答案,但我似乎无法弄清楚如何将答案应用到我的问题中。
var allposts = _context.Posts
.Include(p => p.Comments)
.Include(aa => aa.Attachments)
.Include(a => a.PostAuthor)
.Where(t => t.PostAuthor.Id == postAuthorId).ToList();
附件可以由作者(作者类型)或贡献者(类型贡献者)上传。我想要做的,只是获取附件所有者类型为作者的附件。
我知道这行不通并出现错误:
.Include(s=>aa.Attachments.Where(o=>o.Owner is Author))
我在此处阅读了过滤投影
编辑 - link 文章:
: http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx,
但我无法理解它。
我不想在最后的 where 子句中包含过滤器,因为我想要所有帖子,但我只想检索属于作者的那些帖子的附件。
编辑 2:- Post 请求模式
public abstract class Post : IPostable
{
[Key]
public int Id { get; set; }
[Required]
public DateTime PublishDate { get; set; }
[Required]
public String Title { get; set; }
[Required]
public String Description { get; set; }
public Person PostAuthor { get; set; }
public virtual ICollection<Attachment> Attachments { get; set; }
public List<Comment> Comments { get; set; }
}
Include()
中的 Lambda 可能只指向一个 属性:
.Include(a => a.Attachments)
.Include(a => a.Attachments.Owner);
你的条件对我来说没有意义,因为 Include()
意味着 join
而你要么做要么不做。而且不是有条件的。
你如何用原始格式写这个 SQL?
为什么不只是这个:
context.Attachments
.Where(a => a.Owner.Id == postAuthorId &&
a.Owner.Type == authorType);
?
根据您发布的 link,我可以确认该技巧有效,但仅适用于一对多(或多对一)关系。在这种情况下,您的 Post-Attachment
应该是一对多关系,因此它完全适用。这是您应该拥有的查询:
//this should be disabled temporarily
_context.Configuration.LazyLoadingEnabled = false;
var allposts = _context.Posts.Where(t => t.PostAuthor.Id == postAuthorId)
.Select(e => new {
e,//for later projection
e.Comments,//cache Comments
//cache filtered Attachments
Attachments = e.Attachments.Where(a => a.Owner is Author),
e.PostAuthor//cache PostAuthor
})
.AsEnumerable()
.Select(e => e.e).ToList();
您可以使用 this implementation 的扩展方法(例如)Include2()
。之后,您可以调用:
_context.Posts.Include2(post => post.Attachments.Where(a => a.OwnerId == 1))
以上代码仅包含 Attachment.OwnerId == 1
.
的附件
从 Attachments
导航 属性 中删除 virtual
关键字以防止延迟加载:
public ICollection<Attachment> Attachments { get; set; }
第一种方法:发出两个单独的查询:一个用于 Posts,一个用于附件,然后让关系修复完成其余的工作:
List<Post> postsWithAuthoredAttachments = _context.Posts
.Include(p => p.Comments)
.Include(p => p.PostAuthor)
.Where(p => p.PostAuthor.Id == postAuthorId)
.ToList();
List<Attachment> filteredAttachments = _context.Attachments
.Where(a => a.Post.PostAuthor.Id == postAuthorId)
.Where(a => a.Owner is Author)
.ToList()
关系修复意味着您可以通过 Post 的导航访问这些过滤后的附件 属性
第二种方法:先查询数据库,再查询内存:
var query = _context.Posts
.Include(p => p.Comments)
.Include(p => p.PostAuthor)
.Where(p => p.PostAuthor.Id == postAuthorId)
.Select(p => new
{
Post = p,
AuthoredAttachments = p.Attachments
Where(a => a.Owner is Author)
}
);
我会在这里使用匿名类型
var postsWithAuthoredAttachments = query.ToList()
或者我会创建一个 ViewModel class 来避免匿名类型:
List<MyDisplayTemplate> postsWithAuthoredAttachments =
//query as above but use new PostWithAuthoredAttachments in the Select
或者,如果您真的想打开 Posts:
List<Post> postsWithAuthoredAttachments = query.//you could "inline" this variable
.AsEnumerable() //force the database query to run as is - pulling data into memory
.Select(p => p) //unwrap the Posts from the in-memory results
.ToList()
假设 "a" 属于 "YourType" 类型,条件包含可以通过使用方法扩展来解决,例如
public static class QueryableExtensions
{
public static IQueryable<T> ConditionalInclude<T>(this IQueryable<T> source, bool include) where T : YourType
{
if (include)
{
return source
.Include(a => a.Attachments)
.Include(a => a.Attachments.Owner));
}
return source;
}
}
...然后像使用 .Include 一样使用它,例如
bool yourCondition;
.ConditionalInclude(yourCondition)
EF Core 5.0 即将引入过滤包含。
var blogs = context.Blogs
.Include(e => e.Posts.Where(p => p.Title.Contains("Cheese")))
.ToList();
参考: https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#filtered-include
试试这个
var allposts = _context.Posts
.Include(p => p.Comments)
.Include(a => a.PostAuthor)
.Where(t => t.PostAuthor.Id == postAuthorId).ToList();
_context.Attachments.Where(o=>o.Owner is Author).ToList();
对于网芯
https://docs.microsoft.com/ru-ru/ef/core/querying/related-data/explicit
var allposts = _context.Posts
.Include(p => p.Comments)
.Include(a => a.PostAuthor)
.Where(t => t.PostAuthor.Id == postAuthorId).ToList();
_context.Entry(allposts)
.Collection(e => e.Attachments)
.Query()
.Where(e=> e.Owner is Author)
.Load();
它对 sql 进行了 2 次查询。
我看过一些类似问题的答案,但我似乎无法弄清楚如何将答案应用到我的问题中。
var allposts = _context.Posts
.Include(p => p.Comments)
.Include(aa => aa.Attachments)
.Include(a => a.PostAuthor)
.Where(t => t.PostAuthor.Id == postAuthorId).ToList();
附件可以由作者(作者类型)或贡献者(类型贡献者)上传。我想要做的,只是获取附件所有者类型为作者的附件。
我知道这行不通并出现错误:
.Include(s=>aa.Attachments.Where(o=>o.Owner is Author))
我在此处阅读了过滤投影
编辑 - link 文章: : http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx,
但我无法理解它。
我不想在最后的 where 子句中包含过滤器,因为我想要所有帖子,但我只想检索属于作者的那些帖子的附件。
编辑 2:- Post 请求模式
public abstract class Post : IPostable
{
[Key]
public int Id { get; set; }
[Required]
public DateTime PublishDate { get; set; }
[Required]
public String Title { get; set; }
[Required]
public String Description { get; set; }
public Person PostAuthor { get; set; }
public virtual ICollection<Attachment> Attachments { get; set; }
public List<Comment> Comments { get; set; }
}
Include()
中的 Lambda 可能只指向一个 属性:
.Include(a => a.Attachments)
.Include(a => a.Attachments.Owner);
你的条件对我来说没有意义,因为 Include()
意味着 join
而你要么做要么不做。而且不是有条件的。
你如何用原始格式写这个 SQL?
为什么不只是这个:
context.Attachments
.Where(a => a.Owner.Id == postAuthorId &&
a.Owner.Type == authorType);
?
根据您发布的 link,我可以确认该技巧有效,但仅适用于一对多(或多对一)关系。在这种情况下,您的 Post-Attachment
应该是一对多关系,因此它完全适用。这是您应该拥有的查询:
//this should be disabled temporarily
_context.Configuration.LazyLoadingEnabled = false;
var allposts = _context.Posts.Where(t => t.PostAuthor.Id == postAuthorId)
.Select(e => new {
e,//for later projection
e.Comments,//cache Comments
//cache filtered Attachments
Attachments = e.Attachments.Where(a => a.Owner is Author),
e.PostAuthor//cache PostAuthor
})
.AsEnumerable()
.Select(e => e.e).ToList();
您可以使用 this implementation 的扩展方法(例如)Include2()
。之后,您可以调用:
_context.Posts.Include2(post => post.Attachments.Where(a => a.OwnerId == 1))
以上代码仅包含 Attachment.OwnerId == 1
.
从 Attachments
导航 属性 中删除 virtual
关键字以防止延迟加载:
public ICollection<Attachment> Attachments { get; set; }
第一种方法:发出两个单独的查询:一个用于 Posts,一个用于附件,然后让关系修复完成其余的工作:
List<Post> postsWithAuthoredAttachments = _context.Posts
.Include(p => p.Comments)
.Include(p => p.PostAuthor)
.Where(p => p.PostAuthor.Id == postAuthorId)
.ToList();
List<Attachment> filteredAttachments = _context.Attachments
.Where(a => a.Post.PostAuthor.Id == postAuthorId)
.Where(a => a.Owner is Author)
.ToList()
关系修复意味着您可以通过 Post 的导航访问这些过滤后的附件 属性
第二种方法:先查询数据库,再查询内存:
var query = _context.Posts
.Include(p => p.Comments)
.Include(p => p.PostAuthor)
.Where(p => p.PostAuthor.Id == postAuthorId)
.Select(p => new
{
Post = p,
AuthoredAttachments = p.Attachments
Where(a => a.Owner is Author)
}
);
我会在这里使用匿名类型
var postsWithAuthoredAttachments = query.ToList()
或者我会创建一个 ViewModel class 来避免匿名类型:
List<MyDisplayTemplate> postsWithAuthoredAttachments =
//query as above but use new PostWithAuthoredAttachments in the Select
或者,如果您真的想打开 Posts:
List<Post> postsWithAuthoredAttachments = query.//you could "inline" this variable
.AsEnumerable() //force the database query to run as is - pulling data into memory
.Select(p => p) //unwrap the Posts from the in-memory results
.ToList()
假设 "a" 属于 "YourType" 类型,条件包含可以通过使用方法扩展来解决,例如
public static class QueryableExtensions
{
public static IQueryable<T> ConditionalInclude<T>(this IQueryable<T> source, bool include) where T : YourType
{
if (include)
{
return source
.Include(a => a.Attachments)
.Include(a => a.Attachments.Owner));
}
return source;
}
}
...然后像使用 .Include 一样使用它,例如
bool yourCondition;
.ConditionalInclude(yourCondition)
EF Core 5.0 即将引入过滤包含。
var blogs = context.Blogs
.Include(e => e.Posts.Where(p => p.Title.Contains("Cheese")))
.ToList();
参考: https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#filtered-include
试试这个
var allposts = _context.Posts
.Include(p => p.Comments)
.Include(a => a.PostAuthor)
.Where(t => t.PostAuthor.Id == postAuthorId).ToList();
_context.Attachments.Where(o=>o.Owner is Author).ToList();
对于网芯
https://docs.microsoft.com/ru-ru/ef/core/querying/related-data/explicit
var allposts = _context.Posts
.Include(p => p.Comments)
.Include(a => a.PostAuthor)
.Where(t => t.PostAuthor.Id == postAuthorId).ToList();
_context.Entry(allposts)
.Collection(e => e.Attachments)
.Query()
.Where(e=> e.Owner is Author)
.Load();
它对 sql 进行了 2 次查询。