如果我有一个如下所示的查询:
var forms = repo.GetForms().Where(f => f.SubForms.Any(sf => sf.Classes.Any(c => c.TermId == termId)));
从这里你可以看到我的架构如下:
SubForm
有许多Class
,其中有许多Term
。
我想要的是什么:
所有SubForms
及其Classes
在特定的Term
。
现在发生的事情是,我获得了SubForm
中所有Class
Term
的{{1}}。这意味着SubForm
会返回所有子Class
,而不仅仅是与Term
相关的内容。
例如。我有2个术语,每个术语有2个类的子表单。此查询返回4个类而不是该特定术语中的2个。
我可以用Include('Expression')
说我只想根据条件包含所有类吗?或者我的查询错了?
答案 0 :(得分:6)
使用此:
var subForms = repo.GetSubForms.Select(sf = new {
SubForm = sf,
Classes = sf.Classes.Where(c => c.TermId == termId)
}).ToList()
.Select(t => t.SubForm)
.ToList();
更新:基于@ Slauma的评论:
如果您要加载SubForm
个Class
Term
termId
var subForms = repo.Terms.Where(t => t.Id == termId).Select(t => new {
Term = t,
Class = t.Class,
SubForm = t.Class.SubForm
}).ToList()
.Select(t => t.SubForm).ToList();
,您可以从头到尾;像这样:
Include
或以最简单的方式,您可以在Term
上使用var subForms = repo.Terms.Include("Class.SubForm").Where(t => t.Id == termId)
.Select(t => t.Class.SubForm).ToList();
,请参阅:
SubForm has_many Class has_many Term
注意:我可以从您的问题中了解到,您有这样的关系:
SubForm has_many Class
Term has_many Class
但是,您提供的代码显示的是这样的关系:
{{1}}
如果可以,请提出您的实体,或者更多地解释他们之间的关系。谢谢。
答案 1 :(得分:4)
Include(Where Expression)
不存在。如果您使用Include进行预先加载,您将始终加载所有元素。
通过使用投影可以解决这个问题。基本思想是,您将选择具有所需属性的新匿名类型,以及具有已过滤导航项的另一个属性。 EF会将这些链接在一起,因此您会伪造Include(Where ... )
答案 2 :(得分:1)
你知道有时候我开始迷失在花哨的LINQ扩展方法中,并试图弄清楚如何急切地加载我想要的东西,并采用一个非常简单的“加入”概念。
var result =
(from f in SubForums
from c in Classes
from t in Term
where t.TermId = 1
select new { SubForum = f, Class = c, Term = t }).ToList();
这是一个使用预定义导航属性的简单连接(因此您不必指定连接条件)。您将返回一个匿名类型,其中包含您需要的所有内容。这样做的好处在于Entity Framework会为您进行自动修复,因此,如果您愿意,您可以自由地从您的方法返回SubForum,它将自动包含Class和后续Term引用。
答案 3 :(得分:0)
我不知道关系的确切名称,但它应该是
的内容repo.Terms
.Include("Classes")
.Include("Classes.SubForms")
.SingleOrDefault(x => x.TermId = termId);
// or
repo.GetSubForms
.Include("Classes")
.Where(sf => sf.Classes.Where(c => c.TermId == termId));
答案 4 :(得分:0)
这似乎是一个普遍的要求,当我今年早些时候看时,很难找到解决方案。我最终使用了下面链接中包含的解决方案(我不确定这是我找到的确切解决方案,但它是相同的想法)。希望这有帮助!
Filter the "Includes" table on Entity Framework query
//Found this method to filter our child objects instead of using .include()
var Results = (from res in
(from u in DataContext.User
where u.Type.ToUpper() != "ADMIN"
&& u.StartDate <= DateTime.Now
&& (u.EndDate == null || u.EndDate >= DateTime.Now)
select new
{
User = u,
Access = u.Access.Where(a => a.StartDate <= DateTime.Now
&& (a.EndDate == null || a.EndDate >= DateTime.Now))
}
)
select res);
//The ToArray is neccesary otherwise the Access is not populated in the Users
ReturnValue = Results.ToArray().Select(x => x.User).ToList();