문제

Eclipselink 2.3.2에서 JPA 2.0을 사용하여 제품과 색상 사이에 많은 관계가 있습니다. 제품은 많은 색상을 가질 수 있으며 색상은 많은 제품과 관련 될 수 있습니다. 이 관계는 데이터베이스에서 세 테이블로 표현됩니다.

  • 제품
  • prod_colour (조인 테이블)
  • 색깔

그만큼 prod_colour 테이블에는 두 개의 참조 열이 있습니다 prod_id 그리고 colour_id 관련 부모 테이블에서 product 그리고 colour 각기.

명백히, 엔티티 클래스 Product 색상 세트가 있습니다. java.util.Set<Colour> 이름이 지정되었습니다 colourSet.

엔티티 클래스 Colour 제품 세트가 있습니다. java.util.Set<Product> 이름이 지정되었습니다 productSet.

나는 colour 테이블 기반 prodId 제공 그렇습니다 ~ 아니다 색상을 일치시킵니다 prod_colour 테이블.


해당 JPQL은 다음과 같습니다.

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

다음 SQL 문을 생성합니다.

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

이로 인해 실행 시간 쿼리가되기 때문에 기준 쿼리를 갖는 것이 바람직합니다. 이 복잡한 관계에서 기준 쿼리를 제작할 통찰력이 없습니다.

지금까지 다음 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();

주어진 JPQL에 해당하는 기준 쿼리를 작성하는 방법은 무엇입니까?


편집하다:

이 기준 쿼리 :

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();

결과적으로 다음 SQL 쿼리가 생성됩니다.

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))))

다음 SQL 쿼리를 생성 할 수 있도록이 쿼리를 하위 쿼리와 연관시키는 방법은 무엇입니까?

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   

편집하다:

다음 기준 쿼리와 함께 NOT EXISTS() 공장.

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();

그러나 다음과 같이 불필요한/추가/중복 조인으로 SQL 쿼리를 생성합니다 (원하는 것으로 보이지만 원하는 결과 세트를 반환합니다).

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

이것은 단순히 같아야합니다.

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

서브 쿼리를 가질 수있는 방법이 있습니까? NOT IN() 대신 조항 NOT EXISTS() 그리고이 중복 조인을 제거하려면?

이 쿼리에서 생성 된 중복 조인은 이미 벌레.

도움이 되었습니까?

해결책

다음은 쿼리에 관한 기준입니다 NOT IN() (그러나 나는 선호합니다 NOT EXISTS() ~ 위에 NOT IN()).

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.in(root.get(Colour_.colourId)).value(subquery).not());
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Colour_.colourId)));

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

이것은 다음 SQL 쿼리를 생성합니다.

SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
FROM projectdb.colour t0 
WHERE NOT 
(t0.colour_id IN (
                 SELECT t0.colour_id 
                 FROM prod_colour t3, projectdb.product t2, projectdb.product t1 
                 WHERE (((t1.prod_id = ?) 
                 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

이 쿼리는 원하는 결과 세트를 반환합니다. 그러나 볼 수있는 바와 같이 중복 결합을 생성하지만 이것은 벌레.


편집하다:

견딜 수 없는 같은 쿼리 Hibernate 에서이 기준 쿼리를 작성하는 방법은 잘못된 것 같습니다. 결합과 하위 쿼리의 조합은 올바른 SQL 쿼리를 생성합니다.

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<Colour> subRoot = subquery.from(Colour.class);
subquery.select(subRoot.get(Colour_.colourId));
SetJoin<Colour, Product> join = subRoot.join(Colour_.productSet, JoinType.INNER);

ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
criteriaQuery.where(criteriaBuilder.in(root.get(Colour_.colourId)).value(subquery).not());
subquery.where(criteriaBuilder.equal(join.get(Product_.prodId), parameterExpression));
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Colour_.colourId)));

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

이렇게하면 다음 SQL 쿼리가 생성되어 MySQL에 위임됩니다.

SELECT t0.colour_id, t0.colour_name, t0.colour_hex
FROM projectdb.colour t0
WHERE NOT (t0.colour_id IN 
          (SELECT t1.colour_id
           FROM prod_colour t3, projectdb.product t2, projectdb.colour t1
           WHERE ((t2.prod_id = ?)
           AND ((t3.colour_id = t1.colour_id)
           AND (t2.prod_id = t3.prod_id)))))
ORDER BY t0.colour_id DESC
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top