Nhibernate子查询

时间:2012-08-08 19:16:13

标签: c# nhibernate nhibernate-mapping hibernate-criteria

我在尝试为以下情况编写查询时遇到了很大困难:

在我的核心框架中(由于它不是我们的代码,我无法修改)我有两个类:

[Class(Table = "Teacher")]
public class Teacher
{
    [Id]
    public virtual long? Id {get;set;}

    [Property]
    public virtual string EmployeeNr{get;set;}
}

[Class(Table = "Student")]
public class Student
{
    [Id]
    public virtual long? Id{get;set;}

    [Property]
    public virtual string Name{get;set;}
}

接下来,在我的应用程序层中,我创建了以下类来记录有关学生和教师进行测试的信息

[Class(Table = "TestReports", DiscriminatorValueObject = 1)]
public class TestReport
{
    [Id]
    public virtual long? Id{get;set;}

    [Property]
    public virtual string TestName{get;set;}

    [Property]
    public virtual DateTime Date{get;set;}

    [Property]
    public virtual int Correct{get;set;}

    [Property]
    public virtual int InCorrect{get;set;}

    [Property]
    public virtual int Unanswerd{get;set;}

}

[Subclass(NameType = typeof(StudentTestReport), ExtendsType = typeof(TestReport), DiscriminatorValueObject = 2)]
public class StudentTestReport
{
    [ManyToOne]
    public virtual Student Student{get;set;}
}

[Subclass(NameType = typeof(TeacherTestReport), ExtendsType = typeof(TestReport), DiscriminatorValueObject = 3)]
public class TeacherTestReport
{
    [ManyToOne]
    public virtual Teacher Teacher{get;set;}
}

现在我想要的是查询以获得所有学生和教师的最后一份测试报告但如果教师或学生没有参加任何测试,他们仍应出现在概述中。所以我决定采用AliasToBeanTranformer方法并为报告创建一个包装器对象:

public class TestOverviewWrapper
{
    public virtual string TestName{get;set;}
    public virtual DateTime Date{get;set;}
    public virtual int Correct{get;set;}
    public virtual int InCorrect{get;set;}
    public virtual int Unanswerd{get;set;}
    public virtual long Id{get;set;}
    public virtual string Name{get;set;}
    public virtual string EmployeeNr{get;set;}

    public virtual string Person
    {
            get{ return Name ?? EmployeeNr;}
    }
}

我有很大的麻烦让查询正确,我试着看看我是否只能得到学生和他们的最后一个测试报告,但我不得不将我的子查询的属性投射到包装器对象中。这是我得到了多远:

public IList<TestOverviewWrapper> GetTestOverview()
{
    var crit = SessionFactory.GetCurrentSession().CreateCriteria<Student>("st");

    var dcrit = DetachedCriteria.For<StudentTestReport>("lastTest")
        .Add(Subqueries.PropertyEq("Date",
                                   DetachedCriteria.For<StudentTestReport>("test")
                                       .Add(Restrictions.EqProperty("lastTest.Student", "st.Id"))
                                       .SetProjection(Projections.Max("lastTest.Date"))));

    dcrit.Add(Restrictions.EqProperty("lastTest.Student", "st.Id"));

    crit.Add(Subqueries.Select(dcrit));

    crit.SetProjection(Projections.ProjectionList()
                            .Add(Projections.Property("lastTest.Id")
                            .Add(Projections.Property("lastTest.TestName")
                            .Add(Projections.Property("lastTest.Date")
                            .Add(Projections.Property("lastTest.Correct")
                            .Add(Projections.Property("lastTest.Incorrect")
                            .Add(Projections.Property("lastTest.Unanswerd")
                            .Add(Projections.Property("st.Id")
                            .Add(Projections.Property("st.Name")
                        );

    crit.SetResultTransformer(Transformers.AliasToBean<TestOverview>());
    return crit.List<TestOverviewWrapper>();
}

任何人都可以指出我正确的方向,记住我无法在学生和老师班上添加地图

1 个答案:

答案 0 :(得分:1)

有一个名为Future的便捷功能可以一起批量选择。鉴于以下

public class TestOverviewWrapper
{
    public virtual string TestName { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual int Correct { get; set; }
    public virtual int InCorrect { get; set; }
    public virtual int Unanswerd { get; set; }
    public virtual long Id { get; set; }
    public virtual string Person { get; set; }
}

查询(ies)看起来像

var studentTests = session.CreateCriteria<StudentTestReport>("test")
    .Add(Subqueries.PropertyEq("Date", DetachedCriteria.For<StudentTestReport>()
        .Add(Restrictions.EqProperty("Student", "test.Student"))
        .SetProjection(Projections.Max("lastTest.Date"))))
    .CreateAlias("Student", "student")
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.Property("TestName"), "TestName")
        .Add(Projections.Property("Date"), "Date")
        .Add(Projections.Property("Correct"), "Correct")
        .Add(Projections.Property("Incorrect"), "Incorrect")
        .Add(Projections.Property("Unanswerd"), "Unanswerd")
        .Add(Projections.Property("student.Id"), "Id")
        .Add(Projections.Property("student.Name"), "Person"))
    .SetResultTransformer(Transformers.AliasToBean<TestOverviewWrapper>())
    .Future<TestOverviewWrapper>();

var studentsWithoutTests = session.CreateCriteria<Student>("student")
    .Add(Subqueries.NotExists(DetachedCriteria.For<StudentTestReport>()
        .Add(Restrictions.EqProperty("Student", "student"))))
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.Property("Id"), "Id")
        .Add(Projections.Property("Name"), "Person"))
    .SetResultTransformer(Transformers.AliasToBean<TestOverviewWrapper>())
    .Future<TestOverviewWrapper>();

var teacherTests = session.CreateCriteria<TeacherTestReport>("test")
    .Add(Subqueries.PropertyEq("Date", DetachedCriteria.For<TeacherTestReport>()
        .Add(Restrictions.EqProperty("Teacher", "test.Teacher"))
        .SetProjection(Projections.Max("lastTest.Date"))))
    .CreateAlias("Teacher", "teacher")
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.Property("TestName"), "TestName")
        .Add(Projections.Property("Date"), "Date")
        .Add(Projections.Property("Correct"), "Correct")
        .Add(Projections.Property("Incorrect"), "Incorrect")
        .Add(Projections.Property("Unanswerd"), "Unanswerd")
        .Add(Projections.Property("teacher.Id"), "Id")
        .Add(Projections.Property("teacher.EmployeeNr"), "Person"))
    .SetResultTransformer(Transformers.AliasToBean<TestOverviewWrapper>())
    .Future<TestOverviewWrapper>();

var teacherWithoutTests = session.CreateCriteria<Teacher>("teacher")
    .Add(Subqueries.NotExists(DetachedCriteria.For<TeacherTestReport>()
        .Add(Restrictions.EqProperty("Teacher", "teacher"))))
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.Property("Id"), "Id")
        .Add(Projections.Property("EmployeeNr"), "Person"))
    .SetResultTransformer(Transformers.AliasToBean<TestOverviewWrapper>())
    .Future<TestOverviewWrapper>();

return studentTests.Concat(studentsWithoutTests).Concat(teacherTests).Concat(teacherWithoutTests);