проекция критериев nhibernate приводит к неэффективным запросам

#.net #nhibernate #criteria #projection #nhibernate-criteria

#.net #nhibernate #критерии #прогнозирование #nhibernate-criteria

Вопрос:

Пожалуйста, посмотрите следующий пример, который является очень упрощенной версией моего кода:

 Dim Criteria = Session.CreateCriteria(Of Person)()
Criteria.SetProjection(Projections.Property("Car"))
return Criteria.List(Of Car)()
  

Это работает отлично, однако NHibernate 3.1 создает два запроса для извлечения результатов. Что-то вроде:

 SELECT CarId FROM Person WHERE blababla
  

и затем для каждой строки:

 SELECT color, brand, wheels FROM Car WHERE CarId = ?
  

Это не очень эффективно, поэтому я попытался:

 Criteria.CreateAlias("Car", "Car")
Criteria.SetFetchMode("Car", NHibernate.FetchMode.Join)
  

Который ничего не делает. Как я могу заставить NHibernate выполнить объединение в первом запросе, чтобы в итоге я совершал один круговой переход к серверу MySQL?

Ответ №1:

Когда вы выполняете Projections.Property("Car") , а Car — это ссылка «многие к одному», она просто становится псевдонимом для Projections.Property("Car.Id") . Если вы хотите получить фактический объект Car, у вас есть 2 варианта:

Вариант 1: Укажите все свойства автомобиля в списке проекций.

 Criteria.CreateAlias("Car", "Car")
Criteria.SetFetchMode("Car", NHibernate.FetchMode.Join)
Criteria.SetProjection(Projections.Projectionist() _
           .Add(Projections.Property("Car.Color")) _
           .Add(Projections.Property("Car.Brand")))
  

Если wheels — это другой список объектов, то это становится намного сложнее.

Вариант 2: Укажите запрос с точки зрения Car

 Criteria.CreateCriteria(Of Car)()
Criteria.CreateAlias("Person", "person")
... //specify your criteria
  

Существует также дополнительная опция отказа от использования проекций и получения объекта Person с помощью выбранного объекта Car

Комментарии:

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

Ответ №2:

Я нашел обходной путь, используя подзапрос. Это сработает, но я думаю, что это все равно было бы более эффективным с использованием join, поэтому мой первоначальный вопрос все еще остается в силе. Мой обходной путь:

 var cars = s.CreateCriteria<Cars>()
    .Add(Subqueries.PropertyIn("Id",
        DetachedCriteria.For<Person>()
            .Add(Restrictions.Eq("Name","MyName"))
            .SetProjection(Projections.Property("Car.Id"))
        ))
    .List<Cars>();