给定此对象结构,如何恢复工作项,它是报告,行和学生,但只有学生名称为"Bob"的行(我想省略包含"Alice"和"Claire"的行)。
WorkItem
----Report1(保存在 WorkItem.Reports 集合中)
--------ReportRow1(保存在 Report.ReportRows 集合中)
------------Student.Name = '爱丽丝'--------ReportRow2(保存在 Report.ReportRows 集合中)
------------Student.Name = '鲍勃'--------ReportRow3 (保存在 Report.ReportRows 集合中)
------------Student.Name = '克莱尔'
(对不起格式)
我以为这样的事情会起作用,但它仍然带回所有 3 行
WorkItem found = (from workItem in session.Query<WorkItem>()
from report in workItem.Reports
from row in report.ReportRows
where workItem.Id == 1 && row.Student.Name == "Bob"
select workItem)
.SingleOrDefault<WorkItem>();
更新我也尝试了这个,认为它只会在我实际尝试使用它们时返回结果(它确实如此),但查看日志,它仍然为每个学生做一个选择(我希望最终 foreach 循环中的"where"子句只会带回我感兴趣的那个。
var query = from workItem in session.Query<WorkItem>()
where workItem.Id == 1
select workItem;
WorkItem found = query.SingleOrDefault<WorkItem>();
foreach (var report in found.Reports)
{
foreach (var row in report.ReportRows.Where(x => x.Student.Name == "Bob"))
{
Console.WriteLine("--" + row.Student.Name);
}
}
这是我目前根据Ocelot20的帮助尝试的最佳方法:
var result = (from workItem in session.Query<WorkItem>()
.FetchMany(x => x.Reports)
.ThenFetchMany(y => y.ReportRows.Where(z => z.Student.Name == "Bob"))
where workItem.Id == 1
select workItem);
唯一不起作用的是学生姓名的 Where 子句。如果我删除它,我会得到一个结果(尽管行太多)。如果我能得到正确的where子句,我认为它会带回我想要的东西
从我在这里看到的,你只选择一个WorkItem
.您正在执行限制返回WorkItems
的连接,但您仍然只选择一个WorkItem
,而不是告诉它选择特定的Reports
、ReportRows
等。所以本质上你的查询是说:"只给我一个Id
为 1 的WorkItems
,可以与名为 Bob 的学生一起加入"。请注意缺少:"然后选择仅具有适当ReportRows
的WorkItem
。
我的猜测是你正在做这样的事情:
WorkItem found = (from workItem in session.Query<WorkItem>()
from report in workItem.Reports
from row in report.ReportRows
where workItem.Id == 1 && row.Student.Name == "Bob"
select workItem).SingleOrDefault<WorkItem>();
// Doing something to select `ReportRows` without filtering them:
var someSelection = found.Reports.First().ReportRows;
根据延迟加载设置的方式,ReportRows
甚至不会被查询,直到您在someSelection
行上调用它。此时,它对要筛选的内容一无所知。您在这里有几个选择。首先,您可以在加载WorkItem
后筛选第二个查询中的项目,如下所示:
// Filter on the second query:
var someSelection = found.Reports.First().ReportRows
.Where(rr => rr.Student.Name == "Bob");
或者,您可以直接更改查询以显式选择工作项和相关行:select new { workItem, reportRows = // select specific rows with a where clause here. }
.
最后,还有 nhibernate 功能来指定应将哪些相关实体预加载到所选实体中。我知道实体框架允许您在相关实体上添加Where
子句,但我还没有使用 nhibernate 来了解您是否可以执行以下操作:
var customers = session.Query<Customer>()
.FetchMany(c => c.Orders.Where(o => o.Amount == 100);
如果这有效,这可以应用于您的查询,以告诉 nhibernate 加载具有相关行的WorkItem
,其中Student
名称为"Bob"。