【问题标题】:In NHibernate, using a Disjunction gives double results在 NHibernate 中,使用 Disjunction 会产生双重结果
【发布时间】:2013-05-13 09:13:29
【问题描述】:

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

如果我使用:

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

我得到了我想要的结果。

但是如果我像这样使用析取:

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

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

我不希望使用 QueryOver,因为我正在尝试完成一些使用 QueryOver 难以完成的事情(我尝试做的最终结果是从过滤器的 json 中获取 sql 查询)。

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

更新:

对于 DISTINCT 部分:

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

Projections.Distinct(Projections.Id())

真正的解决方案如 Radim Köhler 所述——子查询的正确使用。

【问题讨论】:

  • 实际返回的 SQL 是什么?您是否也加入了多个表,因为这可能是笛卡尔积的原因
  • 我正在加入 2 个表,并且 4 个条件都在加入的表上。

标签: c# nhibernate join restriction detachedcriteria


【解决方案1】:

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

为什么接收不清晰?

让我们有两个表(如问题下方的一个 cmets 中给出的)

家长:

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

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

这是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<Parent>();

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

现在,我们确实有子选择(DetachedCriteriaSubqueries NHibernate 功能)并且没有更多重复项!

【讨论】:

  • 太棒了,正是我想要的!一个小问题 - 是否可以将添加到子查询的 3 个限制中的每一个都添加为它们自己的分离查询?我希望在不知道查询深度以及限制的数量或类型的情况下自动执行此过程。
  • 我只是担心,如果您将它们单独添加,所有将使用 AND 运算符进行评估。所以,最有可能的是,自动化应该在子选择建筑方面完成......我会说
猜你喜欢
  • 1970-01-01
  • 2015-03-08
  • 2013-03-15
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
  • 1970-01-01
相关资源
最近更新 更多