[Hibernate][Cirteria] Zapytanie z n-warunkami OR

0

Witam,

Chciałbym się dowiedzieć jak stworzyć zapytanie używając Criteria dla n-warunków z operatorem OR.
Przykładowo:

SELECT * FROM table WHERE col1 ilke %a% OR col2 ilike %a% OR col3 ilike %a% .... itd.

Wiem, że jest coś takiego:

crit.add(Restrictions.or(Restrictions.ilike("col1", "a"), Restrictions.ilike("col2","a")));

ale przyjmuje tylko 2 argumenty. I ciężko to zaimplementować w pętli.

Pozdrawiam.

0
crit.add(
    Restrictions.or(
        Restrictions.or(Restrictions.ilike("col1", "a"), Restrictions.ilike("col2","a")),
        Restrictions.or(Restrictions.ilike("col3", "a"), Restrictions.ilike("col4","a"))
   )
  );
0

Hmm tylko jak to wrzucić do pętli:

// dla generowanej listy kolumn
for (int i = 0; i < matchColumns.size(); i++) {
                // generuje IlikeExpression
                final Criterion likeCrit = this.getValueIlikeCriterion(
                        matchColumns.get(i));
}
0

Zauważ, że jest to nic innego jak notacja infiksowa z serią nawiasów. Ja bym to machnął na stos w notacji prefiksowej lub postfixowej. I wtedy ściągał z niego budując wyrażenie. ILIKE oraz OR potraktowałbym po prostu jak operatory. Czym w istocie są. Zauważ, że takie wyrażenie to struktura rekurencyjna - dlatego moim zdaniem najprościej to załatwić właśnie rekurencją.

0

Rzeczywiście rekurencja w tym przypadku to idealne rozwiązanie:

private final Criterion getOrRestrictions(final List<Criterion> crits, 
            final int n) {
        if (!(crits != null && crits.size() > 2)) {
            return null;
        }
        if (n == crits.size() - 2) {
            return Restrictions.or(crits.get(n), crits.get(n+1));
        }
        return Restrictions.or(crits.get(n), this.getOrRestrictions(crits, n+1));
}
0

Rozjaśniłbym nieco czytelność wyrażeń, korzystając ze starych i dobrych praw logiki: :)

private final Criterion getOrRestrictions(final List<Criterion> crits, final int n)
{
        if ((crits == null || crits.size() <= 2))
            return null;

        if (crits.size() == n + 2)
            return Restrictions.or(crits.get(n), crits.get(n+1));

        return Restrictions.or(crits.get(n), this.getOrRestrictions(crits, n+1));
}

Rozumiem, że metoda get(int n) jest przeciążona i ściąga od razu elementy z listy?
Bo używasz size(), więc musisz jakoś skracać listę, a ona jako argument idzie przez referencję, a nie przez wartość. A więc w pełnej długości trafia do każdej instancji tej metody.
Poza tym szepnąłbym jeszcze, że w obu wypadkach modyfikator final, to placebo. ;)
I jeszcze zastanowiłbym się czy nie wywoływać z (n-1) i (n) - bo wtedy wiedziałbym dokładnie, że jak n porównam z zerem, to nic już nie zostanie. A ty porównujesz z n + 2 - więc łatwo o pomyłkę w innej części kodu.

0

Dziękuje za uwagi:

private final Criterion getOrRestrictions(final List<Criterion> crits) {
        if (crits.size() == 0) {
            return null;
        } else if (crits.size() == 1) {
            return crits.get(0);
        } else if (crits.size() == 2) {
            return Restrictions.or(crits.get(0), crits.get(1));
        }
        final Criterion c = crits.remove(2);
        return Restrictions.or(c, getOrRestrictions(crits));
}
0

Piszę z pamięci więc jak coś to doszukaj :D

org.hibernate.criterion.Conjunction con = Restrictions.conjuction();

con.add(Restrictions.eq("zmienna", wartosc");
con.add(Restrictions.eq("zmienna", wartosc");

...

con.add(Restrictions.eq("zmienna", wartosc");

cirt.add(conj)

I masz warunek na or, ile byś warunków nie chciał :)

Pozdrawiam

0

Hehe. Dzięki wielkie.

Disjunction disjunk = Restrictions.disjunction();

1 użytkowników online, w tym zalogowanych: 0, gości: 1