限制使用LINQ返回的深层嵌套子记录

时间:2013-01-21 11:45:10

标签: linq nhibernate linq-to-sql

鉴于此对象结构,我如何带回WorkItem,它的报告,行和学生,但只返回其学生姓名为&#的行39;鲍勃' (我想省略包含' Alice' Claire')的行。

  

工作项
  ---- Report1(在WorkItem.Reports集合中保存)
  -------- ReportRow1(在Report.ReportRows集合中保存)
  ------------Student.Name =' Alice'

     

-------- ReportRow2(保存在Report.ReportRows集合中)
  ------------Student.Name =' Bob'

     

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

更新 我也尝试过这个,认为它只会在我真正尝试使用它们时会带回结果(它确实如此)但是看着日志,它仍然为每个学生做一个选择(我希望&#39;在哪里&# 39;最后一个foreach循环中的子句会带回只是我感兴趣的那个。

    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 子句,我认为它会带回我想要的东西

1 个答案:

答案 0 :(得分:1)

从我在此处看到的内容,您只选择 WorkItem 。您正在进行限制返回的WorkItems的联接,但您仍然仅选择 WorkItem而不是告诉它选择特定的Reports,{{ 1}}等等。基本上你的查询就是这样说:“只给ReportRows WorkItems的{​​1}}可以加入名为Bob的学生”。请注意缺少:“然后选择 Id仅包含相应的WorkItem

我的猜测是你正在做这样的事情:

ReportRows

根据您设置延迟加载的方式,在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");

最后,nhibernate能够指定应将哪些相关实体预加载到您选择的实体中。我知道实体框架允许你在相关实体上添加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); 以及WorkItem名称为“Bob”的相关行。