0

给定这个对象结构,我如何带回一个 WorkItem,它是报告、行和学生,但只有学生的名字是“鲍勃”的行(我想省略包含“爱丽丝”的行'和'克莱尔')。

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

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

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

(对不起格式)

我认为这样的事情会起作用,但它仍然会带回所有 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>();

更新 我也试过这个,认为它只会在我实际尝试使用它们时带回结果(它确实如此)但查看日志,它仍然为每个学生做一个选择(我希望'where'子句在最后的 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子句,我认为它将带回我想要的东西

4

1 回答 1

1

从我在这里看到的,你只选择了一个WorkItem. 您正在执行限制WorkItems返回的连接,但您仍然只选择aWorkItem而不是告诉它选择特定Reports的 ,ReportRows等。所以基本上您的查询是说:“只给我WorkItems一个Id可以与学生连接的 1叫鲍勃”。请注意缺少:“然后使用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");

或者您可以更改您的查询以显式选择工作项和相关行:select new { workItem, reportRows = // select specific rows with a where clause here. }.

最后,休眠功能可以指定应将哪些相关实体预加载到您选择的实体中。我知道实体框架允许您Where在相关实体上添加子句,但我没有使用 nhibernate 来知道您是否可以执行以下操作:

var customers = session.Query<Customer>()
                       .FetchMany(c => c.Orders.Where(o => o.Amount == 100);

如果这可行,这可以应用于您的查询,以告诉 nhibernate 加载名称为“Bob”WorkItem的相关行。Student

于 2013-01-21T15:07:30.190 回答