在NHibernate中,使用Disjunction可以得到双重结果

我正在尝试使用DetachedCriteria进行选择,我想在运行时添加OR分隔的几个条件。

如果我使用:

Restrictions.Or( cond1, Restrictions.Or(cond2, Restrictions.Or(cond3, cond4)) ) 

我得到了我想要的结果。

但如果我像这样使用Disjunction:

 var disjunction = Restrictions.Disjunction(); disjunction.Add(cond1); disjunction.Add(cond2); disjunction.Add(cond3); disjunction.Add(cond4); 

我有cond1和cond2的实体对他们来说是真的,在结果我得到它们两次(在列表结果中相同的实体被返回两次)。

我不想使用QueryOver,因为我正在尝试使用QueryOver来完成一些难以实现的事情(我正在尝试做的最终结果是从filter的json获取sql查询)。

什么导致分离返回双打? 有没有办法在最后添加DISTINCT? 我做错了,我不应该在同一张桌子上使用析取不同的条件吗?

更新:

对于DISTINCT部分:

 criteria.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer()); 

要么

 Projections.Distinct(Projections.Id()) 

真正的解决方案如RadimKöhler所述 – 正确使用子查询。

一个小借口:问题没有提供任何映射,也缺少查询……所以人们只能猜出问题是什么。 但是,我们试着提供一些解释

为什么收到不明显?

我们有两个表(在问题下面的一条评论中给出)

家长:

 ParentId | Name 1 | Parent_A 2 | Parent_B 

儿童:

 ChildId | Color | ParentId 1 | green | 1 2 | grey | 1 3 | gold | 1 4 | green | 2 

如果我们将在纯SQL中创建简单选择,请执行此操作

 SELECT p.ParentId, p.Name FROM Parent AS p INNER JOIN Child AS c ON p.ParentId = c.ParentId WHERE c.Color = 'green' OR c.Color = 'grey' OR c.Color = 'gold' 

这个查询的结果是什么?

 1 | Parent_A 1 | Parent_A 1 | Parent_A 2 | Parent_B 

如果我们将其转换为类似的标准:

 var sesion = ... // get session var parent = sesion.CreateCriteria(); var children = parent.CreateCriteria("Children"); // restrict the children children.Add(Restrictions.Disjunction() .Add(Restrictions.Eq("Color", "green")) .Add(Restrictions.Eq("Color", "grey")) .Add(Restrictions.Eq("Color", "gold")) ); var list = parent .SetMaxResults(10) // does not matter in our example, but ... it should be used always .List(); 

这是Criteria C#代码,它将导致多个Parent (因为事实上,将生成如上所述的相同SQL)

正如我们所看到的,问题肯定不在 NHiberante方面。 真! NHibernate不仅是无辜的,而且还在做所需的事情。

解决方案在子选择中

在SQL中它将是这样的

 SELECT p.ParentId, p.Name FROM Parent AS p WHERE p.ParentId IN ( SELECT c.ParentId FROM Child AS c WHERE c.ParentId = p.ParentId AND c.Color = 'green' OR c.Color = 'grey' OR c.Color = 'gold' ) 

这将为我们提供我们最想要的结果:

 1 | Parent_A 2 | Parent_B 

如何在NHibernate中做到这一点?

 var sesion = ... // get session var parent = sesion.CreateCriteria(); //var children = parent.CreateCriteria("Children"); var children = DetachedCriteria.For(typeof(Child)); // restrict the children children.Add(Restrictions.Disjunction() .Add(Restrictions.Eq("Color", "green")) .Add(Restrictions.Eq("Color", "grey")) .Add(Restrictions.Eq("Color", "gold")) ); // ad SELECT into this sub-select children.SetProjection( Projections.Property("ParentId")); // filter the parent parent .Add(Subqueries.PropertyIn("ParentId", children)); var list = parent .SetMaxResults(10) // does not matter in our example, but ... it should be used always .List(); 

现在,我们确实有sub-select( DetachedCriteriaSubqueries NHibernatefunction)而且没有更多的DUPLICATES!