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))
我在这里读过Filtered Projection
编辑 – 链接到文章:: http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx ,
但我无法理解它。
我不希望在最终的where子句中包含filter,因为我想要所有post,但我只想检索属于作者的那些post的附件。
编辑2: – 请求发布模式
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 Attachments { get; set; } public List Comments { get; set; } }
从您发布的链接中我可以确认该技巧有效,但仅适用于一对多(或多对一)关系。 在这种情况下,你的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 => ee).ToList();
您可以使用此实现的扩展方法(例如) Include2()
。 之后,您可以致电:
_context.Posts.Include2(post => post.Attachments.Where(a => a.OwnerId == 1))
上面的代码仅包含Attachment.OwnerId == 1
。
从“ Attachments
导航属性中删除virtual
关键字以防止延迟加载:
public ICollection
第一种方法:发出两个单独的查询:一个用于post,一个用于附件,让关系修复完成其余的:
List postsWithAuthoredAttachments = _context.Posts .Include(p => p.Comments) .Include(p => p.PostAuthor) .Where(p => p.PostAuthor.Id == postAuthorId) .ToList(); List 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类来避免匿名类型:
List postsWithAuthoredAttachments = //query as above but use new PostWithAuthoredAttachments in the Select
或者,如果你真的想打开post:
List 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()
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);
?
假设“a”属于“YourType”类型,则可以通过使用方法扩展来解决条件包括,例如
public static class QueryableExtensions { public static IQueryable ConditionalInclude (this IQueryable source, bool include) where T : YourType { if (include) { return source .Include(a => a.Attachments) .Include(a => a.Attachments.Owner)); } return source; } }
…然后就像使用它一样使用它。包括,例如
bool yourCondition; .ConditionalInclude(yourCondition)