2013-07-24 41 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子句。

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

,怎麼會被修改,使得它對應於...LEFT OUTER JOIN zone_charge zc ON w.weight_id=zc.weight_id AND zc.zone_id=?

這將生成以下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的hibernate特定擴展。您在標準API中找不到對它的支持。

+0

那麼,我必須只使用JPQL? – Tiny

+0

是的,實際上是HQL,因爲'with'不是JPQL關鍵字。 –

+0

是否支持Hibernate標準?這個查詢反過來將是動態的,並且通過字符串連接進行查詢構造的方式有些乏味。 – Tiny

1

這可以使用新功能join ON clauseJPA 2.1提供的標準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 

它應該是值得一提的是此查詢成功基於Hibernate(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 

ParamterExpression必須刪除才能正常工作,如下所示。

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的監督。