nHibernate集合和别名标准

时间:2010-03-10 13:34:53

标签: nhibernate collections icriteria

我有一个简单的测试对象模型,其中有学校,学校有一群学生。

我想找回一所学校及其所有超过一定年龄的学生。

我执行以下查询,该查询获得特定学校和超过特定年龄的孩子:

    public School GetSchoolAndStudentsWithDOBAbove(int schoolid, DateTime dob)
    {
      var school = this.Session.CreateCriteria(typeof(School))
        .CreateAlias("Students", "students")
        .Add(Expression.And(Expression.Eq("SchoolId", schoolid), Expression.Gt("students.DOB", dob)))
        .UniqueResult<School>();

      return school;
    }

这一切都运行正常,我可以看到查询进入数据库并返回预期的行数。

但是,当我执行以下任一操作时,它会通过运行另一个查询向我提供给定学校的学生总数(无论前面的请求):

        foreach (Student st in s.Students)
        {
            Console.WriteLine(st.FirstName);
        }

        Assert.AreEqual(s.Students.Count, 3);  

任何人都可以解释原因吗?

3 个答案:

答案 0 :(得分:2)

您在School类上进行了查询,并且限制了结果,而不是映射的相关对象。

现在有很多方法可以做到这一点。 你可以像IanL所说的那样制作一个静态过滤器,但它不是很灵活。 您可以像mxmissile一样迭代集合,但这很丑陋(特别是考虑到延迟加载注意事项)

我会提供两种不同的解决方案: 在第一个维护您的查询时,您在集合上触发动态过滤器(维护一个延迟加载的集合)并对数据库进行往返:

var school = GetSchoolAndStudentsWithDOBAbove(5, dob);
IQuery qDob = nhSession.CreateFilter(school.Students, "where DOB > :dob").SetDateTime("dob", dob);
IList<Student> dobedSchoolStudents = qDob.List<Student>();

在第二个解决方案中,只需一次性取得学校和学生:

object result = nhSession.CreateQuery(
    "select ss, st from School ss, Student st 
    where ss.Id = st.School.Id and ss.Id = :schId and st.DOB > :dob")
    .SetInt32("schId", 5).SetDateTime("dob", dob).List();

ss是一个School对象,st是一个学生集合。

这绝对可以使用您现在使用的标准查询(使用预测)来完成

答案 1 :(得分:1)

不幸的是s.Students不会包含您的“查询”结果。您必须为学生创建单独的查询才能实现目标。

foreach(var st in s.Students.Where(x => x.DOB > dob))
     Console.WriteLine(st.FirstName);

警告:根据您的映射情况,它仍将继续第二次访问数据库,它仍将检索所有学生。

我不确定,但您可以使用Projections在一个查询中完成所有这些操作,但我绝不是专家。

答案 2 :(得分:0)

您可以选择过滤数据。如果它有一个查询的单个实例mxmissle选项将是更好的选择。

Nhibernate Filter Documentation

过滤器确实有用,但根据您使用的版本,可能存在过滤集合未正确缓存的问题。