条件include()

6vl6ewon  于 2021-08-01  发布在  Java
关注(0)|答案(9)|浏览(476)

这个问题在这里已经有答案了

ef:include with where子句[副本](5个答案)
4个月前关门了。
我已经看到了一些类似问题的答案,但我似乎无法解决如何将答案应用到我的问题。

var allposts = _context.Posts
            .Include(p => p.Comments)
            .Include(aa => aa.Attachments)
            .Include(a => a.PostAuthor)
            .Where(t => t.PostAuthor.Id == postAuthorId).ToList();

附件可以由作者(type author)或贡献者(type contributor)上传。我想做的是,只获取附件的所有者是author类型的附件。
我知道这不起作用,并给出了一个错误:

.Include(s=>aa.Attachments.Where(o=>o.Owner is Author))

我在这里读过关于过滤投影的文章
编辑-文章链接:http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx,
但我就是想不通。
我不想在最终where子句中包含过滤器,因为我想要所有文章,但我只想检索属于作者的那些文章的附件。
编辑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<Attachment> Attachments { get; set; }
    public List<Comment> Comments { get; set; }
}
lmvvr0a8

lmvvr0a81#

从你发布的链接,我可以确认,伎俩工程,但一个多(或多个一)的关系只。在这种情况下,你的 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();
h7appiyu

h7appiyu2#

efcore5.0即将推出。

var blogs = context.Blogs
    .Include(e => e.Posts.Where(p => p.Title.Contains("Cheese")))
    .ToList();

reference:https用法://docs.microsoft.com/en-us/ef/core/what is new/ef-core-5.0/whatsnew

dfuffjeb

dfuffjeb3#

拆下 virtual 来自您的关键字 Attachments 防止延迟加载的导航属性: public ICollection<Attachment> Attachments { get; set; } 第一种方法:发出两个单独的查询:一个用于帖子,一个用于附件,其余的由关系修复完成:

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类以避免匿名类型:

List<MyDisplayTemplate> postsWithAuthoredAttachments = 
     //query as above but use new PostWithAuthoredAttachments in the Select

或者,如果你真的想拆开柱子:

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()
1qczuiv0

1qczuiv04#

您可以使用扩展方法的这个实现(例如) Include2() . 之后,您可以拨打:

_context.Posts.Include2(post => post.Attachments.Where(a => a.OwnerId == 1))

上面的代码仅包括附件,其中 Attachment.OwnerId == 1 .

j9per5c4

j9per5c45#

试试这个

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();
yzuktlbb

yzuktlbb6#

对于网芯
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次查询。

xghobddn

xghobddn7#

执行查询

{       
    var allposts = _context.Posts
        .Include(p => p.Comments)
        .Include(aa => aa.Attachments)
        .Include(a => a.PostAuthor)
        .AsNoTracking()
        .ToList();

    await allposts.ForEach((FilterByOwner));
}

private async void FilterByOwner(Post post)
{
    post.Attachments = post.Attachments.Where(o => o.Owner is Author);
}
nmpmafwu

nmpmafwu8#

lambda输入 Include() 只能指向属性:

.Include(a => a.Attachments)
.Include(a => a.Attachments.Owner);

你的状况对我来说毫无意义因为 Include() 手段 join 你要么做要么不做。不是有条件的。
您将如何用原始sql编写此代码?
为什么不这样做:

context.Attachments
       .Where(a => a.Owner.Id == postAuthorId &&
                   a.Owner.Type == authorType);

?

avkwfej4

avkwfej49#

假设“a”属于“yourtype”类型,条件include可以通过使用方法扩展来解决,例如。

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;
    }
}

... 然后像你现在使用的一样使用这个。

bool yourCondition;

.ConditionalInclude(yourCondition)

相关问题