JPA criteria query in einer viele-zu-viele-Beziehung

Ich bin mit JPA 2.0, EclipseLink 2.3.2, in dem ich eine viele-zu-viele-Beziehung zwischen Produkten und Ihren Farben. Ein Produkt kann viele Farben und eine Farbe zugeordnet werden kann, die mit vielen Produkten. Diese Beziehung wird ausgedrückt in der Datenbank drei Tabellen.

  • Produkt
  • prod_colour (join-Tabelle)
  • Farbe

Den prod_colour Tabelle hat zwei Spalten referenzieren prod_id und colour_id von seinem zugehörigen übergeordneten Tabellen product und colour bzw.

Als offensichtlich, die entity-Klasse Product hat eine Reihe von Farben - java.util.Set<Colour> mit dem Namen colourSet.

Die entity-Klasse Colour hat eine Reihe von Produkten - java.util.Set<Product> mit dem Namen productSet.

Ich brauche zum abrufen einer Liste von Farben aus der colour Tabelle basierend auf prodId geliefert die nicht nicht passen Sie die Farben in der prod_colour Tabelle.


Den entsprechenden JPQL wäre etwas wie das folgende.

FROM Colour colour 
WHERE colour.colourId 
NOT IN(
SELECT colours.colourId 
     FROM Product product 
     INNER JOIN product.colourSet colours 
     WHERE product.prodId=:id) 
ORDER BY colour.colourId DESC

Generiert es die folgende SQL-Anweisung.

SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
FROM projectdb.colour t0 
WHERE t0.colour_id 
NOT IN (
       SELECT DISTINCT t1.colour_id 
       FROM prod_colour t3, projectdb.product t2, projectdb.colour t1 
       WHERE ((t2.prod_id = ?)
       AND ((t3.prod_id = t2.prod_id) 
       AND (t1.colour_id = t3.colour_id)))) 
ORDER BY t0.colour_id DESC

Da dies wiederum eine Laufzeit Abfragen, wäre es vorzuziehen, um eine Kriterien-Abfrage. Ich habe keine Einsicht zu fabrizieren Kriterien eine Abfrage in dieser komplexen Beziehung.

Ich habe die folgende Abfrage, das ist ganz unabhängig von den vorangehenden JPQL.

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Colour>criteriaQuery=criteriaBuilder.createQuery(Colour.class);
Metamodel metamodel = entityManager.getMetamodel();
EntityType<Colour> entityType = metamodel.entity(Colour.class);
Root<Colour> root = criteriaQuery.from(entityType);
SetJoin<Colour, Product> join = root.join(Colour_.productSet, JoinType.INNER);
ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
criteriaQuery.where(criteriaBuilder.equal(join.get(Product_.prodId), parameterExpression));  

TypedQuery<Colour> typedQuery = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, prodId);
List<Colour> list=typedQuery.getResultList();

How to write a Kriterien Abfrage, entspricht der JPQL gegeben?


EDIT:

Diese Kriterien Abfrage :

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createQuery(Tuple.class);
Metamodel metamodel = entityManager.getMetamodel();
EntityType<Colour> entityType = metamodel.entity(Colour.class);
Root<Colour> root = criteriaQuery.from(entityType);
criteriaQuery.multiselect(root.get(Colour_.colourId));
SetJoin<Colour, Product> join = root.join(Colour_.productSet, JoinType.INNER);
ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
criteriaQuery.where(criteriaBuilder.equal(join.get(Product_.prodId), parameterExpression));

TypedQuery<Tuple> typedQuery = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, prodId);
List<Tuple> list = typedQuery.getResultList();

wiederum das folgende SQL-Abfrage.

SELECT t0.colour_id 
FROM projectdb.colour t0, prod_colour t2, projectdb.product t1 
WHERE ((t1.prod_id = 1) 
AND ((t2.colour_id = t0.colour_id) 
AND (t1.prod_id = t2.prod_id))))

Wie korrelieren diese Abfrage eine Unterabfrage, damit es produzieren kann die folgende SQL-Abfrage?

SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
FROM projectdb.colour t0 
WHERE t0.colour_id 
NOT IN (
       SELECT t0.colour_id 
       FROM projectdb.colour t0, prod_colour t2, projectdb.product t1 
       WHERE ((t1.prod_id = 1) 
       AND ((t2.colour_id = t0.colour_id) 
       AND (t1.prod_id = t2.prod_id))))
ORDER BY t0.colour_id DESC   

EDIT:

Den folgenden Kriterien Abfrage zusammen mit NOT EXISTS() funktioniert.

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Colour>criteriaQuery=criteriaBuilder.createQuery(Colour.class);
Metamodel metamodel = entityManager.getMetamodel();
EntityType<Colour> entityType = metamodel.entity(Colour.class);
Root<Colour> root = criteriaQuery.from(entityType);
criteriaQuery.select(root);
Subquery<Long>subquery=criteriaQuery.subquery(Long.class);
Root<Product> subRoot = subquery.from(Product.class);
subquery.select(root.get(Colour_.colourId));
Predicate paramPredicate = criteriaBuilder.equal(subRoot.get(Product_.prodId), prodId);
Predicate correlatePredicate = criteriaBuilder.equal(root.get(Colour_.productSet), subRoot);
subquery.where(criteriaBuilder.and(paramPredicate, correlatePredicate));
criteriaQuery.where(criteriaBuilder.exists(subquery).not());
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Colour_.colourId)));

TypedQuery<Colour> typedQuery = entityManager.createQuery(criteriaQuery);
List<Colour>list= typedQuery.getResultList();

Es jedoch erzeugt die SQL-Abfrage mit einer unnötigen/zusätzliche/redundante Verknüpfung wie folgt aus (Es gibt das gewünschte Ergebnis einstellen, wenn, wie es zu sein scheint).

SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
FROM projectdb.colour t0 
WHERE 
NOT (EXISTS (
       SELECT t0.colour_id 
       FROM prod_colour t3, projectdb.product t2, projectdb.product t1 
       WHERE (((t1.prod_id = 1) 
       AND (t1.prod_id = t2.prod_id)) 
       AND ((t3.colour_id = t0.colour_id) 
       AND (t2.prod_id = t3.prod_id)))))
ORDER BY t0.colour_id DESC

Sollte dies einfach sein, wie,

SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
FROM projectdb.colour t0 
WHERE 
NOT (EXISTS (
       SELECT t0.colour_id 
       FROM prod_colour t3, projectdb.product t2
       WHERE (((t2.prod_id = 1)) 
       AND ((t3.colour_id = t0.colour_id) 
       AND (t2.prod_id = t3.prod_id)))))
ORDER BY t0.colour_id DESC

Gibt es eine Möglichkeit, um eine Unterabfrage mit der NOT IN() - Klausel anstelle von NOT EXISTS() zu entledigen und diese redundante beitreten?

Die redundante Verknüpfung hergestellt, die von dieser Abfrage wurde bereits berichtet, dass die bug.

InformationsquelleAutor Tiny | 2013-11-07
Schreibe einen Kommentar