使用NHibernate条件的复杂查询



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

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

Id (int)
OrgUnit(一个具有Name字符串属性的对象)
Employee(一个具有下面列出的属性的对象)
TrainingRecords的列表(每个列表包含一个Course对象、一个RequiredBy日期属性和一个Status字符串属性)
一个TNATemplate对象(包含一个限定字符串属性)
客户对象

Employee对象包含以下属性:


在姓前面(字符串)姓(字符串)
职业(字典对象)
Shift(字典)

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

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

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

目前,我们有多个选择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 */)

生成35,000行。然而,报告必须获取组织单元、员工、课程和客户的数据。

下面是我的代码-谁能看到一个方法,使这更有效?:

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>();
更新:

我添加了以下代码,但是Course表仍然被查询多次—子查询似乎从未被调用:

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

我会使用NHibernate Futures来解决这个问题

NHibernate将需要检索主查询中包含的所有OrgUnits, Employees, Courses和Customers。

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

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

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

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

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

当nHibernate需要实例化时,比如说,一个雇员实例,它会看到它已经检索了那个id的雇员并使用那个id。

最新更新