Запрашивать коллекцию с помощью Nhibernate Criteria Api?
-
22-08-2019 - |
Вопрос
У меня есть объект "Estate", и у этого объекта есть коллекция "EstateFeatures" (тип: EstateFeature), а у EstateFeature есть свойство "MyFeatureValue".
Примечание:Это ограниченные свойства для данного вопроса.Все объекты имеют идентификатор и все необходимые параметры и т.д.
Поместье
IList<EstateFeature> EstateFeatures;
Характеристика объекта недвижимости
FeatureValue MyFeatureValue;
Отличительное значение
public virtual long Id;
Я пытаюсь приобрести недвижимость, которая имеет данное FeatureValue.Id
DetachedCriteria query = DetachedCriteria.For<Estate>();
Conjunction and = new Conjuction();
foreach (var id in idCollection)
and.Add(Expression.Eq("MyFeatureValue.Id",id);
query
.CreateCriteria("EstateFeatures")
.Add(and);
IList<Estate> estates = query.GetExecutableCriteria(session).List<Estate>();
Ничего не вернулось из этого запроса, я делаю что-то не так?
Спасибо
Решение
Вам нужно будет убедиться, что вы подключаетесь к MyFeatureValue один раз для каждой функции, которую вы хотите иметь в своем Поместье.
Один из способов - вызвать .Создайте ALIAS для каждой итерации, присвоите ей уникальный псевдоним, затем добавьте выражение "aliasX.Id"
foreach (var id in idCollection) { query = query.CreateAlias("MyFeatureValue", "feature" + id) .Add(Expression.Eq("feature" + id + ".Id",id); }
На самом деле не помню, как работает синтаксис, написал это из головы, не уверен, нужно ли вам также повторно объявлять запрос :)
Тем не менее, я думаю, это поможет вам начать.
Редактировать:Поскольку ошибка в Criteria API не позволяет вам связывать коллекцию несколько раз с помощью createAlias или createCriteria, вам необходимо прибегнуть к HQL.
http://derek-says.blogspot.com/2008/06/duplicate-association-path-bug-in.html
(Спящий режим также страдает от той же проблемы)
select e FROM Estate AS e INNER JOIN e.MyFeatureValue AS fv1 INNER JOIN e.MyFeatureValue AS fv2 WHERE fv1.Id = 3 AND fv2.Id = 13
вам нужно будет динамически создавать HQL, чтобы ваши псевдонимы стали уникальными (fv1, fv2, fvX ...)
Другие советы
Если я правильно понимаю, я думаю, что что-то подобное может сработать
CreateCriteria(typeof(Estate))
.CreateAlias("EstateFeatures", "estatefeature")
.Add(Restrictions.In("estatefeature.MyFeatureValue.Id", ids))
.List<Estate>();
Какой запрос NHibernate сгенерировал для вас ?Вы можете проверить это, используя свойство show_sql config.
Насколько я понимаю ваш запрос, вы пытаетесь получить все объекты, которые имеют заданный набор функций.Я думаю, это сгенерирует запрос, который выглядит следующим образом
SELECT ....
FROM Estates
INNER JOIN Features
WHERE Feature.Id = 1 AND Feature.Id = 2 ...
Если вы хотите получить все объекты, которые содержат все указанные функции, я думаю, вам придется использовать Дизъюнкцию, чтобы NHibernate извлекал все объекты, которые имеют хотя бы одну из этих функций.Затем в вашем клиентском коде вам нужно будет проверить каждое свойство в вашем "клиентском коде", так что в конечном итоге вы получите только те свойства, которые обладают всеми функциями.
Я не знаю , есть ли эффективный способ позволить NHibernate справиться с этим ...
Код выглядит так, как будто вы передаете список FeaturesValueIds и хотите получить список, содержащий все эти функции.Если это так, я бы взглянул на генерируемый SQL-код и запустил его в базе данных, чтобы узнать, следует ли вам что-либо возвращать.
В противном случае, если вы ищете Список, содержащий какие-либо из передаваемых вами функций, вам следует использовать Дизъюнкцию, а не Конъюнкцию.
exec sp_executesql N'SELECT TOP 3 id11_1_, Address11_1_, Title11_1_, Descript4_11_1_,
Price11_1_, Discount11_1_, ForBankL7_11_1_, AddDate11_1_, LastUpdate11_1_,
IsVisible11_1_, ViewCount11_1_, SaleOrRent11_1_, LocationId11_1_, StaffId11_1_,
CategoryId11_1_, id27_0_, EstateId27_0_, FeatureV3_27_0_ FROM (SELECT ROW_NUMBER()
OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.id11_1_, query.Address11_1_,
query.Title11_1_, query.Descript4_11_1_, query.Price11_1_, query.Discount11_1_,
query.ForBankL7_11_1_, query.AddDate11_1_, query.LastUpdate11_1_, query.IsVisible11_1_,
query.ViewCount11_1_, query.SaleOrRent11_1_, query.LocationId11_1_, query.StaffId11_1_,
query.CategoryId11_1_, query.id27_0_, query.EstateId27_0_, query.FeatureV3_27_0_,
query.__hibernate_sort_expr_0__ FROM (SELECT this_.id as id11_1_, this_.Address as
Address11_1_, this_.Title as Title11_1_, this_.Description as Descript4_11_1_, this_.Price
as Price11_1_, this_.Discount as Discount11_1_, this_.ForBankLoan as ForBankL7_11_1_,
this_.AddDate as AddDate11_1_, this_.LastUpdate as LastUpdate11_1_, this_.IsVisible as
IsVisible11_1_, this_.ViewCount as ViewCount11_1_, this_.SaleOrRent as SaleOrRent11_1_,
this_.LocationId as LocationId11_1_, this_.StaffId as StaffId11_1_, this_.CategoryId as
CategoryId11_1_, estatefeat1_.id as id27_0_, estatefeat1_.EstateId as EstateId27_0_,
estatefeat1_.FeatureValueId as FeatureV3_27_0_, CURRENT_TIMESTAMP as
__hibernate_sort_expr_0__ FROM Estate this_ inner join EstateFeature estatefeat1_ on
this_.id=estatefeat1_.EstateId WHERE this_.CategoryId = @p0 and
(estatefeat1_.FeatureValueId = @p1 and estatefeat1_.FeatureValueId = @p2 and
estatefeat1_.FeatureValueId = @p3 and estatefeat1_.FeatureValueId = @p4 and
estatefeat1_.FeatureValueId = @p5 and estatefeat1_.FeatureValueId = @p6 and
estatefeat1_.FeatureValueId = @p7)) query ) page WHERE page.row > 0 ORDER BY
__hibernate_sort_expr_0__',N'@p0 bigint,@p1 bigint,@p2 bigint,@p3 bigint,@p4 bigint,@p5
bigint,@p6 bigint,@p7 bigint',@p0=3,@p1=7,@p2=8,@p3=9,@p4=10,@p5=11,@p6=12,@p7=16
Это выглядит так, как будто ты хочешь or
(Disjunction
) вместо and
(Conjunction
).Прямо сейчас вы ищете EstateFeature
s объектов таким образом, что каждый объект имеет несколько различных Id
s, который, кажется, не является тем, чего вы хотите.
var or = new Disjunction();
foreach(var id in idCollection)
or.Add(Expression.Eq("MyFeatureValue.Id", id);
var query = DetachedCriteria.For<Estate>();
query
.CreateCriteria("EstateFeatures")
.Add(and);
var estates = query.GetExecutableCriteria(session).List<Estate>();
Я тоже пробовал это, но результат тот же:
DetachedCriteria features = DetachedCriteria.For<FeatureValue>();
features.SetProjection(Projections.Property("Id"));
features.Add(Property.ForName("Id").EqProperty("value.Id"));
var and = new Conjunction();
foreach (var l in FeatureIdCollection)
and.Add(Expression.Eq("Id", l));
features.Add(and);
query.CreateCriteria("EstateFeatures")
.CreateCriteria("MyFeatureValue","value")
.Add(Subqueries.Exists(features));