#.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>();