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