Abfragen zur Sammlung mit der Nhibernate Criteria API?
-
22-08-2019 - |
Frage
Ich habe eine „Estate“-Entität und diese Entität hat eine Sammlung „EstateFeatures“ (Typ:EstateFeature) und EstateFeature hat eine Eigenschaft „MyFeatureValue“.
Notiz:Dies sind die eingeschränkten Eigenschaften für die Frage.Alle Entitäten haben eine ID und alles Notwendige usw
Anwesen
IList<EstateFeature> EstateFeatures;
EstateFeature
FeatureValue MyFeatureValue;
FeatureValue
public virtual long Id;
Ich versuche, Immobilien zu erhalten, die die angegebene FeatureValue.Id haben
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>();
Von dieser Abfrage wurde nichts zurückgegeben. Mache ich etwas falsch?
Danke
Lösung
Sie müssen sicherstellen, dass Sie MyFeatureValue für jede Funktion, die Ihr Anwesen haben soll, einmal beitreten.
Eine Möglichkeit besteht darin, .CreateAlias für jede Iteration aufzurufen, ihr einen eindeutigen Alias zu geben und dann den Ausdruck „aliasX.Id“ hinzuzufügen.
foreach (var id in idCollection) { query = query.CreateAlias("MyFeatureValue", "feature" + id) .Add(Expression.Eq("feature" + id + ".Id",id); }
Ich kann mich nicht wirklich erinnern, wie die Syntax funktioniert, ich habe das aus meinem Kopf heraus geschrieben, bin mir auch nicht sicher, ob Sie die Abfrage neu deklarieren müssen :)
Ich denke jedoch, dass dies Ihnen den Einstieg erleichtern wird.
BEARBEITEN:Da ein Fehler in der Criteria-API Sie daran hindert, eine Sammlung mehrmals mit CreateAlias oder CreateCriteria zu verknüpfen, müssen Sie auf HQL zurückgreifen.
http://derek-says.blogspot.com/2008/06/duplicate-association-path-bug-in.html
(Hibernate leidet ebenfalls unter dem gleichen Problem)
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
Sie müssen die HQL dynamisch erstellen, damit Ihre Aliase eindeutig werden (fv1, fv2, fvX ...)
Andere Tipps
Wenn ich das richtig verstanden, ich glaube, so etwas wie dies funktionieren könnte
CreateCriteria(typeof(Estate))
.CreateAlias("EstateFeatures", "estatefeature")
.Add(Restrictions.In("estatefeature.MyFeatureValue.Id", ids))
.List<Estate>();
Welche Abfrage hat NHibernate für Sie generieren? Sie können dies überprüfen, indem Sie die show_sql Config Eigenschaft.
Wie ich Ihre Frage zu sehen, Sie versuchen, alle Stände zu erhalten, die einen bestimmten Satz von Funktionen hat. Ich denke, wird dies eine Abfrage erzeugen, die wie
siehtSELECT ....
FROM Estates
INNER JOIN Features
WHERE Feature.Id = 1 AND Feature.Id = 2 ...
Wenn Sie alle Stände abrufen möchten, die alle angegebenen Merkmale enthalten, ich glaube, Sie werden eine Disjunktion verwenden müssen, so dass NHibernate alle Estates abruft, die mindestens eines dieser Merkmale aufweisen.
Dann in Ihrem Client-Code, haben Sie jedes Estate in Ihrem Client-Code 'überprüfen, so dass Sie schließlich nur mit Estates am Ende, die alle Funktionen.
Ich weiß nicht, ob es eine effiziente Möglichkeit der Vermietung NHibernate damit umgehen ist ...
Der Code sieht aus wie Sie in einer Liste von FeaturesValueIds und wollen eine Liste unterwegs sind, die alle diese Eigenschaften hat. Wenn das der Fall ist, habe ich einen Blick auf die SQL nehmen würde, die erzeugt wird, und es in der Datenbank ausführen, um zu sehen, wenn Sie etwas immer wieder werden sollte.
Andernfalls, wenn Sie für eine Liste suchen, der Sie in sind vorbei eine der Eigenschaften hat, sollten Sie eine Disjunktion verwenden, anstatt eine Konjunktion.
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
Es sieht aus wie Sie or
(Disjunction
) statt and
(Conjunction
) wollen. Gerade jetzt, Sie suchen nach EstateFeature
s Objekten, so dass jedes Objekt mehr verschiedenen Id
s hat, was nicht zu sein, was scheint, Sie wollen.
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>();
Ich habe auch versucht dies, aber das Ergebnis ist das gleiche:
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));