0

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

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

我执行以下查询,获取给定学校和特定年龄以上的孩子:

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

谁能解释为什么?

4

3 回答 3

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 是 Student 集合。

这绝对可以使用您现在使用的条件查询来完成(使用投影)

于 2010-03-11T09:24:44.133 回答
1

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

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

警告:根据您的映射,这仍然会第二次访问数据库,它仍然会检索所有学生。

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

于 2010-03-10T15:19:55.777 回答
0

您确实可以选择过滤数据。如果存在查询 mxmissle 选项的单个实例,那将是更好的选择。

休眠过滤器文档

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

于 2010-03-10T15:29:07.073 回答