# JPQL Query erstellen



## cowabunga1984 (14. Sep 2008)

Hi zusammen,

ich habe folgende Methode geschrieben:


```
private List<Entry> getEntries() {
		EntityManager em = Main.getInstance().getActivePawotag()
				.getEntityManager();
		Query query;

		if (tagFilter.isEmpty()) {
			query = em.createQuery("SELECT DISTINCT e " + "FROM Entry e "
					+ "ORDER BY e.id");
		} else {
			// TODO easier???
			String queryString = "SELECT DISTINCT e "
					+ "FROM Entry e, IN (e.tags) t WHERE t.id>0 ";
			
			for (Tag tag : tagFilter) {
				queryString += "AND t.id=" + tag.getId() + " ";
			}

			query = em.createQuery(queryString);
		}

		return query.getResultList();
	}
```

Jetzt frage ich mich, ob es nicht möglich ist den Code viel einfacher zu schreiben?!?

Gruß
cowabunga


----------



## Guest (14. Sep 2008)

Die zweite Query liefert sicherlich nie etwas. Die Tag-Id kann nicht gleichzeitig mehrere Werte annehmen.

```
if( tagFilter.isEmpty() ) {
   return em.createQuery("select distinct e from Entry e order by e.id")
            .getResultList();
}
return em.createQuery(
   "select distinct e"
  +"  from Entry e"
  +"       left join e.tags t"
  +" where t.id in (:idList)"
  +" order by e.id"
).setParameter("idList", tagFilter.extractTagIds()) // Liefert List<Long> mit Ids der Tags
 .getResultList();
```
Mach noch NamedQueries daraus, dann wird es noch kürzer im Code

```
if( tagFilter.isEmpty() ) {
   return em.createNamedQuery(Entry.ALL)
            .getResultList();
}
return em.createNamedQuery(Entry.ALLBYTAGIDLIST)
            .setParameter("idList", tagFilter.extractTagIds()) // Liefert List<Long> mit Ids der Tags
            .getResultList();
```


----------



## cowabunga1984 (15. Sep 2008)

Hi,

Du hattes Recht, mein 2. Query hat nichts returned 

Leider hat auch Dein Vorschlag nicht genau das gemacht, was ich wollte. Meine aktuelle Lösung sieht jetzt wie folgt aus:

```
private List<Entry> getEntries() {
		EntityManager em = Main.getInstance().getActivePawotag()
				.getEntityManager();
		Query query = em.createQuery("SELECT DISTINCT e FROM Entry e "
				+ "ORDER BY e.id");

		List<Entry> allEntries = query.getResultList();
		List<Entry> filteredEntries = new ArrayList<Entry>();

		for (Entry entry : allEntries) {
			if (entry.getTags().containsAll(this.tagFilter)) {
				filteredEntries.add(entry);
			}
		}

		return filteredEntries;
	}
```

Funktioniert soweit ganz gut. Leider werden die Entries erst im nachhinein gefiltert und nicht bereits durch den Query. Verbesserungsvorschläge? 

Gruß
cowabunga


----------



## Guest (16. Sep 2008)

Wie wäre es mit sowas?

```
SELECT e
  FROM Entry e
 WHERE e.id IN (
	SELECT t.entry.id
	  FROM Tag t
	 WHERE t.id IN (:idList)
	 GROUP BY t.entry.id
   HAVING COUNT(t.id) = :idListSize
)
```
Aufruf mit der Tag-Id Liste und der Länge der Liste.

Es setzt aber voraus, dass deine Datenbank GROUP BY und HAVING ohne die Aggregation zu projiizieren zulässt (H2 z.B. macht es ohne zu zicken).


----------



## Guest (16. Sep 2008)

Alternativ gleich die Tags mitladen und Javaseitig filtern (so wie du es hast). Spart dir die n+1 Zugriffe beim Lesen der Tags.
	
	
	
	





```
SELECT DISTINCT e FROM Entry e JOIN FETCH e.tags ORDER BY e.id
```


----------



## cowabunga1984 (16. Sep 2008)

Hab mich für Version 2 entschieden. Danke für deine Hilfe!

Gruß
cowabunga


----------

