2013-07-24 4 views
1

다음 SQL 쿼리에 대한 조건 쿼리가 필요합니다.JPA에서 ON 조건을 가진 외부 조인

SELECT w.weight_id, w.weight, zc.charge 
FROM weight w 
LEFT OUTER JOIN zone_charge zc ON w.weight_id=zc.weight_id 
AND zc.zone_id=?    <------- 
ORDER BY w.weight ASC 

대응 JPQL 쿼리 같은 것,

SELECT w.weightId, w.weight, zc.charge 
FROM Weight w 
LEFT JOIN w.zoneChargeSet zc 
WITH zc.zone.zoneId=:id  <------- 
ORDER BY w.weight 

나는 기준, 특히 WITH zc.zone.zoneId=:id과 동일하게 재현 할 수 없습니다.


다음 쿼리는 where 절을 사용합니다. 이 ...LEFT OUTER JOIN zone_charge zc ON w.weight_id=zc.weight_id AND zc.zone_id=?

에 해당 있도록 수정 될 수있는 방법

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder(); 
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createTupleQuery(); 
Root<Weight> root = criteriaQuery.from(entityManager.getMetamodel().entity(Weight.class)); 
SetJoin<Weight, ZoneCharge> join = root.join(Weight_.zoneChargeSet, JoinType.LEFT); 

ParameterExpression<Long>parameterExpression=criteriaBuilder.parameter(Long.class); 
criteriaQuery.where(criteriaBuilder.equal(join.get(ZoneCharge_.zoneTable).get(ZoneTable_.zoneId), parameterExpression)); 
criteriaQuery.multiselect(root.get(Weight_.weightId), root.get(Weight_.weight), join.get(ZoneCharge_.charge)); 
criteriaQuery.orderBy(criteriaBuilder.asc(root.get(Weight_.weight))); 
TypedQuery<Tuple> typedQuery = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, 1L); 
List<Tuple> list = typedQuery.getResultList(); 

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

SELECT weight0_.weight_id AS col_0_0_, 
     weight0_.weight  AS col_1_0_, 
     zonecharge1_.charge AS col_2_0_ 
FROM social_networking.weight weight0_ 
     LEFT OUTER JOIN social_networking.zone_charge zonecharge1_ 
        ON weight0_.weight_id = zonecharge1_.weight_id 
WHERE zonecharge1_.zone_id =? 
ORDER BY weight0_.weight ASC 

답변

1

with 연산자는 JPQL에 대한 최대 절전 모드의 확장입니다. 기준 API에서 지원을 찾을 수 없습니다.

+0

따라서 JPQL 만 사용해야합니까? – Tiny

+0

예, 실제로 'with'는 JPQL 키워드가 아니기 때문에 HQL입니다. –

+0

최대 절전 모드 기준에서 지원됩니까? 이 질의는 동적 일 것이고, 문자열 연결에 의한 질의 생성은 다소 지루합니다. – Tiny

1

JPA 2.1의 새로운 기능인 join ON clause을 사용하여 제공되는 기준 API와 함께이 작업을 수행 할 수 있습니다. 따라서, 질문에서 주어진 기준 쿼리는 다음과 같이 재 작성 될 수있다.

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder(); 
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createQuery(Tuple.class); 
Root<Weight> root = criteriaQuery.from(entityManager.getMetamodel().entity(Weight.class)); 

ListJoin<Weight, ZoneCharge> join = root.join(Weight_.zoneChargeList, JoinType.LEFT); 
criteriaQuery.multiselect(root.get(Weight_.weightId), root.get(Weight_.weight), join.get(ZoneCharge_.charge)); 

ParameterExpression<Long>parameterExpression=criteriaBuilder.parameter(Long.class); 
join.on(criteriaBuilder.equal(join.get(ZoneCharge_.zoneTable).get(ZoneTable_.zoneId), parameterExpression)); 

criteriaQuery.orderBy(criteriaBuilder.asc(root.get(Weight_.weight))); 
List<Tuple> list = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, 1L).getResultList(); 

다음과 같은 원하는 SQL 쿼리가 생성됩니다.

SELECT weight0_.weight_id AS col_0_0_, 
     weight0_.weight  AS col_1_0_, 
     zonecharge1_.charge AS col_2_0_ 
FROM social_networking.weight weight0_ 
     LEFT OUTER JOIN social_networking.zone_charge zonecharge1_ 
        ON weight0_.weight_id = zonecharge1_.weight_id 
         AND (zonecharge1_.zone_id =?) 
ORDER BY weight0_.weight ASC 

그것은이 쿼리가 최대 절전 모드 (4.3.5 final)에 성공하지만 동일한 쿼리가 예기치 않게 다음을 제외하고는 EclipseLink (2.5.1)에 실패 언급 할 가치가 있어야한다.

java.lang.IllegalArgumentException: No parameter with name : Parameter[name=null] was found within the query: ReportQuery(referenceClass=Weight). 
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:548) 
    at admin.beans.ZoneChargeBean.getZoneChargeList(ZoneChargeBean.java:83) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081) 
    at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153) 
    at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4695) 
    at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:630) 
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822) 
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:582) 
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883) 
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822) 
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:582) 
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163) 
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883) 
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822) 
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:369) 
    at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4667) 
    at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4655) 
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212) 
    ... 72 more 

은 다음과 같이 작동해야합니다.

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder(); 
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createQuery(Tuple.class); 
Root<Weight> root = criteriaQuery.from(entityManager.getMetamodel().entity(Weight.class)); 

ListJoin<Weight, ZoneCharge> join = root.join(Weight_.zoneChargeList, JoinType.LEFT); 

criteriaQuery.multiselect(root.get(Weight_.weightId), root.get(Weight_.weight), join.get(ZoneCharge_.charge)); 
join.on(criteriaBuilder.equal(join.get(ZoneCharge_.zoneTable).get(ZoneTable_.zoneId), 1L)); 

criteriaQuery.orderBy(criteriaBuilder.asc(root.get(Weight_.weight))); 
List<Tuple> list = entityManager.createQuery(criteriaQuery).getResultList(); 

EclipseLink 2.5.1에서 감독해야합니다.