使用NHibernate Criteria API查询集合?

4
我有一个名为“Estate”的实体,该实体拥有一个集合“EstateFeatures”(类型为EstateFeature),而EstateFeature有一个属性“MyFeatureValue”。
注:这些是问题的有限属性。所有实体都有一个ID和所有必要内容。
IList<EstateFeature> EstateFeatures;

EstateFeature

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

这个查询没有返回任何结果,我做错了什么吗?

谢谢。

7个回答

8
如果我理解正确,我认为这样做可能会有效。
CreateCriteria(typeof(Estate))
     .CreateAlias("EstateFeatures", "estatefeature")
     .Add(Restrictions.In("estatefeature.MyFeatureValue.Id", ids))
     .List<Estate>();

是的,有点儿……我已经在做这个了,但我有一个 ID 集合。感谢您的回答。 - Barbaros Alp

2
你需要确保为每个你想要的房地产功能加入MyFeatureValue一次。其中一种方法是为每次迭代调用.CreateAlias,给它一个唯一的别名,然后添加表达式“aliasX.Id”。
foreach (var id in idCollection)
{
   query = query.CreateAlias("MyFeatureValue", "feature" + id)
                .Add(Expression.Eq("feature" + id + ".Id",id));
}
我不确定语法如何,我是凭感觉写的,也不确定是否需要重新声明query :) 无论如何,我认为这将让你有所启发。
编辑:由于标准API中的错误限制您使用CreateAlias或CreateCriteria多次关联集合,因此您需要求助HQL。 http://derek-says.blogspot.com/2008/06/duplicate-association-path-bug-in.html (Hibernate也存在同样的问题)
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...)。

我收到了一个错误,提示“重复的关联路径:MyFeatureValue”。 - Barbaros Alp
没错,这有点是 Criteria API 的一个 bug。你将不得不转向使用 HQL,因为我认为他们还没有修复它。 - jishi
谢谢jishi,我现在要尝试一下。等我完成后再联系你。 - Barbaros Alp

2
你可以通过使用show_sql配置属性来检查NHibernate生成的查询。
根据我看到的查询,你正在尝试获取具有给定功能集的所有物业。 我认为这将生成一个类似于以下的查询:
SELECT ....
FROM Estates
INNER JOIN Features
WHERE Feature.Id = 1 AND Feature.Id = 2 ...

如果您想检索包含所有指定特征的所有房地产,我认为您需要使用Disjunction,这样NHibernate就会检索具有其中一个特征的所有房地产。 然后,在您的“客户端代码”中,您需要检查每个房地产,以便最终仅保留具有所有功能的房地产。
我不知道是否有一种有效的方法让NHibernate处理这个问题...


我的查询不是返回了拥有所有特征(而不仅仅是其中至少一个特征)的房地产吗? - Barbaros Alp
你能详细解释一下吗? "然后,在你的客户端代码中,你需要检查每个房地产,以便最终只剩下具有所有功能的房地产。" - Barbaros Alp

1

代码看起来像是你正在传递一个FeaturesValueIds列表,并希望得到包含所有这些特征的列表。如果是这样的话,我建议你查看所生成的SQL,并在数据库中运行它,以查看是否应该返回任何内容。

否则,如果你正在寻找一个包含任何你传入的特征的列表,那么你应该使用Disjunction而不是Conjunction。


当我使用“或”条件时,查询会返回一些值,但它们是具有任何这些特征的结果。我想要只获取具有这些特征的结果?那么我的查询不正确吗? - Barbaros Alp
{DetachableCriteria(MyFeatureValue.Id = 7 and MyFeatureValue.Id = 8 and MyFeatureValue.Id = 9 and MyFeatureValue.Id = 10 and MyFeatureValue.Id = 11 and MyFeatureValue.Id = 12 and MyFeatureValue.Id = 16)} 这是一个查询(DetachedCriteria)。 - Barbaros Alp
不,这是Detached Criteria,SQL正在路上。 - Barbaros Alp

0
    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

3
那真漂亮。请给我一分钟。 - RKitson
我在条件中没有看到您要求 CategoryID = 3 的 Estates,这可能与此有关。 - RKitson
这不就是“where CategoryID=3”中的WHERE,其作用是让this_.CategoryId = @p0吗? - Barbaros Alp
正确,但你在 Criteria 中哪里要求了它? - RKitson
哦,我明白了。它在代码的上面。这就是为什么我没有提到它。另外,我尝试了没有category=3,结果也一样。你有其他建议还是我走错了路? - Barbaros Alp

0

看起来你想要使用或(Disjunction)而不是与(Conjunction)操作。目前,你正在搜索每个物业特征对象都具有多个不同的Id,这似乎不是你想要的。

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

我认为我需要使用“并且”连接词,因为我需要具有仅 featureIdcollection 特征集合的 Estates。它必须只包含它们,不多不少。这不是“并且”连接词吗? - Barbaros Alp
我以前尝试过,好的我得到了Estates,但其中一个Estate出现了多次。 我使用查询 .SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer()); 但它无法很好地与我的分页一起工作。SetMaxResults和SetFirstResult - Barbaros Alp
它只在每个页面中区分值,而不是整个结果集中,我知道这是另一个话题,但你有任何想法吗? - Barbaros Alp

-1

我也尝试过这个,但结果还是一样的:

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));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接