具有NHibernate条件的复杂查询

具有NHibernate条件的复杂查询,nhibernate,criteria,Nhibernate,Criteria,我在以下任务中使用NHibernate标准时遇到问题 我有一个具有以下属性的对象TNA,以及其他属性 Id(int) OrgUnit(具有名称字符串属性的对象) Employee(具有下列属性的对象) 培训记录列表(每个记录包含课程对象、RequiredBy日期属性和状态字符串属性) TNATemplate对象(包含限定字符串属性) 顾客对象 Employee对象包含以下属性,以及其他属性: 名字(字符串) 姓氏(字符串) 职业(字典对象) 班次(字典) dictionary对象包含一个id(i

我在以下任务中使用NHibernate标准时遇到问题

我有一个具有以下属性的对象TNA,以及其他属性

Id(int)
OrgUnit(具有名称字符串属性的对象)
Employee(具有下列属性的对象)
培训记录列表(每个记录包含课程对象、RequiredBy日期属性和状态字符串属性)
TNATemplate对象(包含限定字符串属性)
顾客对象

Employee对象包含以下属性,以及其他属性:

名字(字符串)
姓氏(字符串)
职业(字典对象)
班次(字典)

dictionary对象包含一个id(int)和一个描述(string)

用户可以在我们的系统中创建自己的过滤器,这些过滤器是使用标准实现的

我需要查询TNA对象以生成一个相当复杂的报告,但我们的数据结构使这变得很困难

目前,我们有多个Select N+1问题,我发现难以解决

我们当前的条件(无任何筛选)生成以下sql语句:

SELECT this_1_.OrgUnit_Id   as y0_,
       this_.Employee_id       as y1_,
       trainingre1_.Course_id  as y2_,
       trainingre1_.RequiredBy as y3_,
       this_.TNATemplate_id    as y4_,
       trainingre1_.TNAStatus  as y5_,
       this_1_.Customer_id  as y6_
FROM   tblTNA this_
       inner join tblModule this_1_
         on this_.Module_id = this_1_.Id
       left outer join tblTraining trainingre1_
         on this_.Module_id = trainingre1_.TNA_Id
       left outer join tblModule trainingre1_1_
         on trainingre1_.Module_id = trainingre1_1_.Id
WHERE  this_1_.Customer_id = 9 /* @p0 */
       and this_1_.IsArchive = 0 /* @p1 */
       and this_1_.IsActive = 1 /* @p2 */
       and not (trainingre1_.TNAStatus = 3 /* @p3 */)
这将产生35000行。但是,报告必须随后获取组织单位、员工、课程和客户的数据

以下是我的代码-有人能想出一种更有效的方法吗

DetachedCriteria dc = this.BuildPermissions(moduleUser, typeof(TNA));
ICriteria criteria = dc.GetExecutableCriteria(this.Session);

criteria.SetReadOnly(true);
criteria.SetFlushMode(FlushMode.Never);

criteria.SetFetchMode("OrgUnit", FetchMode.Join);
criteria.SetFetchMode("Employee", FetchMode.Join);
criteria.SetFetchMode("TrainingRecords", FetchMode.Join);
criteria.SetFetchMode("TrainingRecords.Course", FetchMode.Join);
criteria.SetFetchMode("TNATemplate", FetchMode.Join);

criteria.CreateAlias("TrainingRecords", "TrainingRecords", NHibernate.SqlCommand.JoinType.LeftOuterJoin);
criteria.Add(Restrictions.Not(Restrictions.Eq("TrainingRecords.TNAStatus", TNAStatus.Optional)));

ProjectionList projectionList =
    Projections.ProjectionList()    
        .Add(Projections.Property("OrgUnit"), "OrgUnit")
        .Add(Projections.Property("Employee"), "Employee")
        .Add(Projections.Property("TrainingRecords.Course"), "Course")
        .Add(Projections.Property("TrainingRecords.RequiredBy"), "RequiredBy")
        .Add(Projections.Property("TNATemplate"), "TNATemplate")
        .Add(Projections.Property("TrainingRecords.TNAStatus"), "TNAStatus")
        .Add(Projections.Property("Customer"), "Customer");

ICriteria result = criteria.SetProjection(projectionList)
    .SetResultTransformer(Transformers.AliasToBean<TrainingMatrix>());

return result.List<TrainingMatrix>();
DetachedCriteria dc=this.BuildPermissions(moduleUser,typeof(TNA));
ICriteria criteria=dc.GetExecutableCriteria(this.Session);
条件。SetReadOnly(true);
criteria.SetFlushMode(FlushMode.Never);
SetFetchMode(“OrgUnit”,FetchMode.Join);
条件.SetFetchMode(“雇员”,FetchMode.Join);
条件.SetFetchMode(“TrainingRecords”,FetchMode.Join);
条件.SetFetchMode(“TrainingRecords.Course”,FetchMode.Join);
SetFetchMode(“TNATemplate”,FetchMode.Join);
CreateAlias(“TrainingRecords”、“TrainingRecords”、NHibernate.SqlCommand.JoinType.LeftOuterJoin);
添加(Restrictions.Not(Restrictions.Eq(“TrainingRecords.TNAStatus”,TNAStatus.Optional));
投射者投射者=
投影。投影列表()
.Add(Projections.Property(“OrgUnit”),“OrgUnit”)
.Add(预测、财产(“员工”),“员工”)
.Add(Projections.Property(“TrainingRecords.Course”),“Course”)
.Add(Projections.Property(“TrainingRecords.RequiredBy”),“RequiredBy”)
.Add(Projections.Property(“TNATemplate”),“TNATemplate”)
.Add(Projections.Property(“TrainingRecords.TNAStatus”),“TNAStatus”)
添加(预测、财产(“客户”),“客户”);
ICriteria结果=criteria.SetProjection(projectionList)
.SetResultTransformer(Transformers.AliasToBean());
返回result.List();
更新:

我添加了以下代码,但课程表仍被多次查询-子查询似乎从未被调用:

    criteria.Future<TrainingMatrix>();

    var myCourseSubQuery = QueryOver.Of<Course>()
        .Where(a => a.Customer.Id == moduleUser.Customer.Id)
        .Select(x => x.Id, x => x.CourseName, x => x.CourseDate);

    IEnumerable<Course> courses = this.Session.QueryOver<Course>()
                                          .WithSubquery.WhereProperty(c => c.Id)
                                                .In(myCourseSubQuery)
                                          .Future();

    ICriteria result = criteria.SetProjection(projectionList)
                               .SetResultTransformer(Transformers.AliasToBean<TrainingMatrix>());

    return result.List<TrainingMatrix>();
criteria.Future();
var myCourseSubQuery=QueryOver.Of()
.Where(a=>a.Customer.Id==moduleUser.Customer.Id)
.Select(x=>x.Id,x=>x.CourseName,x=>x.CourseDate);
IEnumerable courses=this.Session.QueryOver()
.WithSubquery.WhereProperty(c=>c.Id)
.In(子查询)
.Future();
ICriteria结果=criteria.SetProjection(projectionList)
.SetResultTransformer(Transformers.AliasToBean());
返回result.List();
我将使用

NHibernate需要检索主查询中的所有组织单位、员工、课程和客户

因此,对于这些项中的每一项,创建一个未来查询

(我使用的是伪代码和QueryOver语法的不可编译混合体,但它应该能让人明白这一点)

IEnumerable customers=s.QueryOver()
.WithSubquery.WhereProperty(c=>c.Id)
.In(myCustomerSubQuery)
.Future();
IEnumerable couse=s.QueryOver()
.WithSubquery.WhereProperty(c=>c.Id)
.In(子查询)
.Future();

然后将最后的
TrainingMatrix
查询也作为将来的查询

因为它们是
Future
查询,所以当您解析其中任何一个查询时,它们都将成批运行。您将在数据库的一次往返中有效地获得所需的一切


当nHibernate需要实例化(比如)一个雇员实例时,它将看到它已经检索到该id的雇员并使用该id。

Hi Andrew。谢谢你的回答。你能提供更多的细节吗,因为我对此很不熟悉。myCustomerSubQuery和my CourseSubQuery是如何定义的?另外,为了使示例中的最后一个查询成为未来查询,我是否只使用criteria.future()?大概,当我返回result.List()时,这一切都会正常工作?我已经更新了原始问题,尝试使用未来的查询。然而,这似乎没有效果。我假设我做错了什么,但我不知道那会是什么。尝试将
result.List()
替换为
result.Future().ToList()
。这将使它成为一个未来查询,并强制它与课程未来查询一起运行?您只需要
Id
属性。我不知道如果一个子查询选择多个属性会发生什么,但我的预测是它不会起作用。非常感谢Andrew,这很管用。我不能让它只使用id,我想添加三个属性可能会解决这个问题。把它放回id,在上面添加代码,就这样做了
 IEnumerable<Customer> customers = s.QueryOver<Customer>()
                                      .WithSubquery.WhereProperty(c => c.Id)
                                             .In(myCustomerSubQuery)
                                     .Future();
 IEnumerable<Course> couse = s.QueryOver<Course>()
                                       .WithSubquery.WhereProperty(c => c.Id)
                                             .In(myCourseSubQuery)
                                       .Future();