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.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Folgenden sind die Kriterien Abfrage über
NOT IN()
(ich jedoch lieberNOT EXISTS()
überNOT IN()
).Daraus ergibt sich folgende SQL-Abfrage.
Diese Abfrage liefert das gewünschte Ergebnis einstellen. Es jedoch, erzeugt eine redundante Verbindung wie gesehen werden kann, aber dies scheint ein bug.
Edit:
Versuchen die gleiche Abfrage auf Hibernate, die Art und Weise des Schreibens dieser Kriterien Abfrage sieht falsch. Eine Kombination von join und subquery-Ergebnis in der Produktion der korrekte SQL-Abfrage.
Daraus ergibt sich folgende SQL-Abfrage, die wiederum Delegierte zu MySQL.