# JPA Criteria, BETWEEN,



## ayibogan (12. Mai 2011)

HI, 
hab folgende Criteria in der AbstrachtFacade:


```
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
Predicate condition1 = cb.between(cq.from(entityClass).get("latitude"), minLat, maxLat);
Predicate condition2 = cb.between(cq.from(entityClass).get("longitude"), minLong, maxLong);
cq.where(condition1).where(condition2);
javax.persistence.Query q = getEntityManager().createQuery(cq);
return q.getResultList();
```

Leider bekomme ich statt einer gefilterten Liste, einfach alle DB-Einträge von der jeweiligen Entity und das sogar doppelt.

Folgender Statement liefert genau das, was ich brauche:


```
SELECT u FROM UserEntity u WHERE 
u.latitude BETWEEN :minLatitude AND :maxLatitude 
AND 
u.longitude BETWEEN :minLongitude AND :maxLongitude
```


```
Query query = em.createQuery(queryString);
```


Weiß jemand woran das liegen könnte?


----------



## Deadalus (12. Mai 2011)

Distinct vergessen? Versuchs mal so: 

```
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
Predicate condition1 = cb.between(cq.from(entityClass).get("latitude"), minLat, maxLat);
Predicate condition2 = cb.between(cq.from(entityClass).get("longitude"), minLong, maxLong);
cq.where(condition1, condition2).distinct(true);
javax.persistence.Query q = getEntityManager().createQuery(cq);
return q.getResultList();
```


----------



## ayibogan (12. Mai 2011)

Das Distinct hat zwar die doppelten Einträge entfernt (komisch bei JPQL braucht ich das nie explizit in die query eingeben), aber er gibt mir immer noch die kommplette Tabelle aus, statt die Begrenzung mit BETWEEN zu beachten.


----------



## SlaterB (12. Mai 2011)

between ist ja nun kein Zauberkasten, sondern mit einfacheren Mitteln ausdrückbar


> JPQL also includes the following conditionals:
> * [NOT] BETWEEN: Shorthand for expressing that a value falls between two other values. The following two statements are synonymous:
> SELECT x FROM Magazine x WHERE x.price >= 3.00 AND x.price <= 5.00
> SELECT x FROM Magazine x WHERE x.price BETWEEN 3.00 AND 5.00


hast du in der Hinsicht alles ausprobiert?

fange an mit 
SELECT u FROM UserEntity u 
wieviele Ergebnisse?
dann
SELECT u FROM UserEntity u WHERE u.latitude >= 0.5  (testweise feste Parameter, minimiert Fehlerquellen)
wieviele Ergebnisse?

es folgen
SELECT u FROM UserEntity u WHERE u.latitude >= 0.5 and  u.latitude <= 0.7 
und dann dasselbe mit BETWEEN-Syntax

verwende sinnvolle feste Werte, so dass sowohl oben als auch unten User rausfallen und an den Ergebnis-Zahlen alles genau geprüft werden kann,

wenn mit einem Attribut alles nachvollziehbar ist, dann kommt das zweite hinzu, erst alles mit <=, >=, dann alles mit BETWEEN,
evtl. auch kombinieren, bei so vielen ANDs dürfen es gerne auch Klammern sein,
ein OR ist auch allein zum Lernen ein Test wert

da ist soviel auszuprobieren, nicht nur ne Query mit unbekannten Parametern posten und dann nix weiter tun..

edit:
ah, reichlich spät sehe ich, dass es an SQL/ HQL mal wieder gar nicht liegt sonder die blöden Criterias,
da folgt gleich hoffentlich noch ein edit


----------



## ayibogan (12. Mai 2011)

JPQL querry bringt doch das gewünschte Ergebnis...,
das Problem liegt in der Umsetzung als Criteria, wobei die query ja Identisch ist, daher muss das wohl an der syntax liegen.


----------



## SlaterB (12. Mai 2011)

jo, habe ich dann auch letztlich erkannt, siehe edit im letzen Posting,
dass zweimal where() nicht viel Sinn ergibt kann nicht schwer zu erraten sein,
hast du irgendein Lehrbuch/ Tutorial/ Ausbildung dazu genossen oder bastelst du salopp gesagt beliebig rum?

ich selber kann dazu auch nur raten/ ausprobieren bzw. Internet-Beispiele anschauen, 
worauf du anscheinend auch nicht kommst oder mir die Arbeit überlässt (ich bin jetzt gehässig, ignorieren  )



> CriteriaBuilder cb = JpaHandle.get().getCriteriaBuilder();
> CriteriaQuery cq = cb.createQuery(this.baseClass);
> Root entity_ = cq.from(this.baseClass);
> Predicate restrictions = null;
> ...


Paddy's Weblog: Examples using JPA 2.0
funktionierts in der Richtung?
(edit: so ein richtig tolles Beispiel zweiter Bedingungen ist das auch wieder nicht.., die vorletzte Zeile muss wohl 2x aufgeführt werden,
suche ansonsten nach Predicate, conjunction usw.  )


----------



## ayibogan (12. Mai 2011)

generell tippe ich nach Gefühl immer erst alles rein und poste dann es im forum...
Natürlich recherchiere ich im Web und ziehe mir nicht alles aus der Nase...


```
Predicate predicate1 = cb.conjunction();
        Predicate predicate2 = cb.conjunction();
        predicate1.getExpressions().add(cb.between(cq.from(entityClass).get("latitude"), minLat, maxLat));
        predicate2.getExpressions().add(cb.between(cq.from(entityClass).get("longitude"), minLong, maxLong));
        cq.where(cb.and(predicate1, predicate2));
```

als auch

```
Predicate condition1 = cb.between(cq.from(entityClass).get("latitude"), minLat, maxLat);
        Predicate condition2 = cb.between(cq.from(entityClass).get("longitude"), minLong, maxLong);
        cq.where(cb.and(condition1, condition2)).distinct(true);
```

funktionieren auch nicht.

JPA Criteria API by samples – Part-I | Altuure Blog


----------



## SlaterB (12. Mai 2011)

das zweite sieht ja nach Lehrbuch besser aus, ich würde jetzt selber testen, habe aber die entsprechenden APIs nicht, 
Hibernate Criteria funktioniert anders, da kann ich nix machen

die erste deiner beiden neuen Versionen ist bisschen wild, eher am von mir geposteten Beispiel ist vielleicht:

```
Predicate restrictions = null;
restrictions = cb.conjunction();
restrictions = cb.and(restrictions, cb.between(cq.from(entityClass).get("latitude"), minLat, maxLat));
restrictions = cb.and(restrictions, cb.between(cq.from(entityClass).get("longitude"), minLong, maxLong));
cq.where(restrictions);
```
wobei ich das kaum nachvollziehen kann, besonderns was conjunction() leistet?

----

und du bist dir sicher dass z.B. die Parameter stimmen?
hast du getestet ob die Criteria-Query mit jeweils nur einem der Betweens funktioniert?

wenn diese bereits nicht gehen, dann liegt es vielleicht an dem wiederholten 'cq.from(entityClass)' 
welches ich in den anderen Beispielen nicht sehe, dort wird ja z.B. 

```
Root<SimpleBean> from = criteriaQuery.from(SimpleBean.class);
```
nur einmal geschrieben und genau dieses from-Objekt mehrfach verwendet


----------



## ayibogan (13. Mai 2011)

> dann liegt es vielleicht an dem wiederholten 'cq.from(entityClass)'
> welches ich in den anderen Beispielen nicht sehe



Daran lags zwar nicht, aber hat mich auf folgendes aufmerksam gemacht:

```
cq.select(cq.from(entityClass));
```

Nachdem ich das rausgenommen habe, funktionieren alle heir auf der Seite geposteten Varianten einwandfrei.
Jetzt hab ich die Qual der Wahl, oder herausfinden welche Variante am ehsten konform ist.

Nochmals danke für das Helfen.


----------

