В NHibernate использование дизъюнкции дает двойной результат

Я пытаюсь сделать выбор с DetachedCriteria, я хочу добавить несколько условий, разделенных ИЛИ во время выполнения.

Если я использую:

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 (конечный результат того, что я пытаюсь сделать, это получить SQL-запрос из json фильтров).

Что заставляет дизъюнкцию возвращать дубли? Есть ли способ добавить DISTINCT в конце? Я делаю это неправильно, и я не должен использовать дизъюнкцию для разных условий на одном столе?

ОБНОВИТЬ:

Для ОТЛИЧНОЙ части:

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

или же

Projections.Distinct(Projections.Id())

Реальное решение, как утверждает Радим Келер, - правильное использование подзапроса.

1 ответ

Решение

Небольшое оправдание: вопрос не дает никакого отображения, также отсутствует запрос... Так что можно только догадываться, в чем проблема. Но давайте попробуем дать какое-то объяснение

Почему прием не внятный?

Давайте две таблицы (как указано в одном из комментариев ниже вопроса)

родитель:

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#, который приведет к нескольким родителям (из-за того факта, что тот же 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>();

Теперь у нас есть суб-выбор (DetachedCriteria а также Subqueries Особенности NHibernate) и не более дубликатов!

Другие вопросы по тегам