Запросы критериев NHibernate - Как связать логические операторы - PullRequest
0 голосов
/ 20 марта 2012

Я ищу пример того, как создать запрос критерия, который привел бы к SQL, подобному этому (или с эквивалентным эффектом):

SELECT x, y, z
FROM SomeTable tbl
WHERE tbl.a = 'some value' 
  AND (
    (tbl.b = '1' AND tbl.c = 'whatever1' AND tbl.d = 123) OR
    (tbl.b = '2' AND tbl.c = 'whatever2' AND tbl.d = 456) OR
    (tbl.b = '3' AND tbl.c = 'whatever3' AND tbl.d = 789)
  )

При создании запроса у меня есть список данных фильтра (который заполняет данные, которые идут после «И»), а также дополнительный параметр (который заполняет часть «некоторое значение» выше).

По сути, мой вопрос заключается в том, как объединить AND и OR при построении запроса такого типа? API для Expression.And и Expression.Or принимает только один левый и правый критерий, а не цепочку.

Кто-нибудь знает, где я могу найти пример для этого?

Кстати, часть x, y, z (после SELECT) в настоящее время не имеет значения, так как кажется, что я могу сделать это с помощью проекции (пока не получил).

Ответы [ 3 ]

1 голос
/ 21 марта 2012

С помощью API критериев вы можете использовать классы Conjunction (AND) и Disjunction (OR).Например, см. этот поток стекового потока

1 голос
/ 20 марта 2012

Не существует такой вещи, как логическое связывание операторов.Вышеприведенное также можно записать как

(tbl.b = '1' AND tbl.c = 'whatever1' AND tbl.d = 123) OR
    ((tbl.b = '2' AND tbl.c = 'whatever2' AND tbl.d = 456) OR
     (tbl.b = '3' AND tbl.c = 'whatever3' AND tbl.d = 789))

То есть логические операторы ВСЕГДА имеют левый и правый параметры.

При этом побитовые операторы перегружены на Restriction, поэтомуследующие работы:

criteria.Add(Restrictions.Eq("a", "some value") &
             (Restrictions.Eq("b", 1) & Restrictions.Eq("c", "whatever1") |
             (Restrictions.Eq("b", 2) & Restrictions.Eq("c", "whatever2"))))
             //...etc...
0 голосов
/ 21 марта 2012

Что ж, похоже, моя первоначальная попытка действительно сработала, поэтому я опубликую, как я это сделал, на случай, если это кого-нибудь заинтересует. Это выглядит примерно так:

    public IEnumerable<Entity> Filter(FilterRequest filterRequest)
    {
        var criteria = session.CreateCriteria("Entity");

        criteria.Add(
            Expression.And(
                CreateItemCriteria(filterRequest),
                CreateKeysCriteria(filterRequest)));

        return criteria.List<Entity>();
    }

    private static ICriterion CreateItemCriteria(FilterRequest filterRequest)
    {
        return Restrictions.Eq("a", filterRequest.ItemId);
    }

    private ICriterion CreateKeysCriteria(FilterRequest filterRequest)
    {
        ICriterion finalCriterion = null;

        for (int i = 0; i < filterRequest.Keys.Count; i++)
        {
            var currentKeyCriterion = CreateKeyCriterion(filterRequest.Keys[i]);

            finalCriterion = finalCriterion == null
                ? currentKeyCriterion
                : Expression.Or(finalCriterion, currentKeyCriterion);
        }

        return finalCriterion;
    }

    private ICriterion CreateKeyCriterion(Key key)
    {
        return Expression.AllEq(new Dictionary<string, object>
            {
                { "b", Key.b },
                { "c", Key.c },
                { "d", Key.d },
            });
    }

Не очень элегантно, но работает, и результат SQL точно такой, как я хотел.

...