Коллекции nHibernate и критерии псевдонимов - PullRequest
0 голосов
/ 10 марта 2010

У меня есть простая модель тестового объекта, в которой есть школы, а в школе есть коллекция учеников.

Я бы хотел найти школу и всех ее учеников старше определенного возраста.

Я выполняю следующий запрос, в котором указывается данная школа и дети старше определенного возраста:

    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 ]

2 голосов
/ 11 марта 2010

Вы сделали запрос на уроке School и ограничили свои результаты на нем, а не на связанных объектах.

Теперь есть много способов сделать это. Вы можете сделать статический фильтр, как сказал IanL, но он не очень гибкий. Вы можете просто выполнить итерацию коллекции, как mxmissile, но это уродливо и медленно (особенно учитывая соображения отложенной загрузки)

Я бы предложил 2 разных решения: Во-первых, вы поддерживаете запрос, который у вас есть, и запускаете динамический фильтр для коллекции (поддерживая ленту с отложенной загрузкой) и выполняете обход в базу данных:

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.

И это определенно можно сделать, используя запрос критерия, который вы используете сейчас (используя Прогнозы)

1 голос
/ 10 марта 2010

К сожалению s.Students не будет содержать ваши "запрошенные" результаты. Вам нужно будет создать отдельный запрос для студентов, чтобы достичь своей цели.

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

Предупреждение: Это все равно сделает вторую поездку в БД в зависимости от вашего отображения, и все равно получит всех студентов.

Я не уверен, но вы могли бы использовать Projection для выполнения всего этого в одном запросе, но я ни в коем случае не эксперт в этом.

0 голосов
/ 10 марта 2010

У вас есть возможность фильтрации данных. Если это единственный экземпляр параметра запроса, то лучшим вариантом будет mxmissle.

Документация по фильтру Nhibernate

Фильтры действительно используются, но в зависимости от используемой версии могут возникнуть проблемы, когда фильтрованные коллекции не кэшируются правильно.

...