C# 实体框架中的条件Include()

C# 实体框架中的条件Include(),c#,entity-framework,linq,linq-to-entities,C#,Entity Framework,Linq,Linq To Entities,我已经看到了一些类似问题的答案,但是我似乎不知道如何将答案应用到我的问题上 var allposts = _context.Posts .Include(p => p.Comments) .Include(aa => aa.Attachments) .Include(a => a.PostAuthor) .Where(t => t.PostAuthor.Id == postAu

我已经看到了一些类似问题的答案,但是我似乎不知道如何将答案应用到我的问题上

var allposts = _context.Posts
            .Include(p => p.Comments)
            .Include(aa => aa.Attachments)
            .Include(a => a.PostAuthor)
            .Where(t => t.PostAuthor.Id == postAuthorId).ToList();
附件可以由作者(类型Author)或参与者(类型Contributor)上传。我想做的是,只获取附件所有者为Author类型的附件

我知道这不起作用,并给出了一个错误:

.Include(s=>aa.Attachments.Where(o=>o.Owner is Author))
我在这里读过有关过滤投影的内容

编辑-链接到文章: :

但我就是想不起来

我不想在final 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; }
}
公共抽象类Post:IPostable
{
[关键]
公共int Id{get;set;}
[必需]
public DateTime PublishDate{get;set;}
[必需]
公共字符串标题{get;set;}
[必需]
公共字符串说明{get;set;}
公共人物后作者{get;set;}
公共虚拟ICollection附件{get;set;}
公共列表注释{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);

从你发布的链接中,我可以确认这个技巧有效,但只适用于一对多(或多对一)关系。在这种情况下,您的
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();
您可以使用扩展方法(例如
Include2()
)。之后,您可以拨打:

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

上面的代码仅包括
Attachment.OwnerId==1的附件
附件
导航属性中删除
虚拟
关键字以防止延迟加载:

公共ICollection附件{get;set;}

第一种方法:发出两个单独的查询:一个用于帖子,一个用于附件,其余的由relationship fix完成:

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()
我会在这里使用匿名类型

var postsWithAuthoredAttachments = query.ToList()
或者创建ViewModel类以避免匿名类型:

List<MyDisplayTemplate> postsWithAuthoredAttachments = 
     //query as above but use new PostWithAuthoredAttachments in the Select
列出PostSwithAuthoridAttachments=
//如上所述进行查询,但在选择中使用新的PostWithAuthoredAttachments
或者,如果您真的想打开帖子:

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()
List postsWithAuthoredAttachments=query//您可以“内联”这个变量
.AsEnumerable()//强制数据库查询按原样运行-将数据拉入内存
.Select(p=>p)//从内存结果中打开帖子
托利斯先生()
假设“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;
    }
}

EF Core 5.0即将推出过滤包

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

试试这个

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();
网芯

它对sql进行2次查询。

执行查询

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


请给我们看一下
帖子
模式好吗?@DarkKnight-请看edit@grayson你要求做的是不可能的
Linq2Sql
将把代码转换成原始的
SQL
,并通过连接返回子行。您不能在
SQL
中执行这种条件联接。您唯一的选择是删除
。包括(aa=>aa.Attachments)
,并进行第二次查询,根据所有者是否是作者/贡献者返回附件。谢谢。我对这一切都很陌生。我可以这样做以获得所需类型的附件,但我不知道如何将其合并回帖子中。我的DisplayTemplate来自Post并显示Post。Attachmentshow您将使用原始SQL编写:从表1中选择*x连接表2 y on x.fkey=y.fkey和(带y的条件)@Austin_Anderson:这不是条件连接,是吗?连接始终是条件连接。这通常是以PKEY为条件的。但是,您可以在pkey和其他条件下进行total join。事实上,由于联接通常在大型数据集中是首选的。@DiscipleMichael:联接从来都不是有条件的,它要么存在,要么不存在。而表演一场可能代价高昂。好的性能调整是消除连接,你们知道它不会产生任何结果。在U-SQL中,它通常使用动态SQL完成。但这里有一个关于EF的问题。我是否需要在调用后将“_context.Configuration.LazyLoadingEnabled=true;”添加到renable lazy loading中?@grayson是的,如果你想重新启用它。@我知道这个问题很老,但我最近的问题被标记为与这个问题重复,我的要求是当
附件
具有其他子属性时,它们在结果中不可用。链接到我的问题@Krtti我不确定你的问题是否可以用这里的答案解决,实际上我不太理解你的问题(根据你在链接问题中的描述,至少有两种理解方式)。还有人在那里添加了一个答案,看起来这是正确的理解问题的一种方式。我的答案中的想法非常简单,可以应用,当它不起作用时,可能不适用。最后,我很长时间没有与EF和Linq to entity合作,所以我可能帮不了你多少忙。@无望了,不用担心,我的问题得到了回答,感谢您花时间与informHi联系,在没有帖子附件的情况下,这似乎不起作用。A、 我错过了什么这是个玩笑还是什么?真是天才。。!这对我有帮助!这不起作用,因为您试图对帖子列表使用显式加载。但是.Entry()只能在单个实体上使用。代码格式化之前必须至少有4个空格,并确保缩进符合易读性标准。这将在客户端过滤响应。如果您认为数据库非常小,那么这将对性能造成影响。你应该
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();
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();
{       
    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);
}