2014-10-31 94 views
3

我這是爲了檢查是否有FileMagazines是在Magazines列表下Subscription以下規範:NPE與規格/謂詞JPA的findAll

public static Specification<File> getContainingMagazines(final long subscriptionId){ 
    return new Specification<File>() { 
     @Override 
     public Predicate toPredicate(Root<File> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 

     Subquery<Subscription> subscriptionSubquery = query.subquery(Subscription.class); 
     Root<Subscription> subscriptionRoot = subscriptionSubquery.from(Subscription.class); 
     ListJoin<Subscription, Magazine> subscriptionMagazineJoin = subscriptionRoot.join(Subscription_.magazines); 

     Path<Long> subscriptionIdPath = subscriptionRoot.get(Subscription_.id); 

     subscriptionSubquery. 
       select(subscriptionRoot). 
       where(cb.equal(subscriptionIdPath, subscriptionId)); 

     ListJoin<File, Magazine> magazinesJoin = root.join(File_.magazines); 

     return cb.and(magazinesJoin.get(Magazine_.id).in(subscriptionMagazineJoin.get(Magazine_.id))); 
     } 
    }; 
} 

而在我的服務我]丟這樣的:

public int findFilesWithSubscription(long subscriptionId) { 
     List<File> fileList = fileRepository.findAll(FileSpecs.getContainingMagazines(subscriptionId)); 
     return fileList.size(); 
    } 

所涉及的實體如下:

@Entity 
@Table(name = "nim_file") 
public class File 

@ManyToMany(fetch = FetchType.LAZY) 
@JoinTable(
     name = "nim_file_magazines", 
     joinColumns = @JoinColumn(name = "file_id"), 
     inverseJoinColumns = @JoinColumn(name = "magazine_id") 
) 
private List<Magazine> magazines; 

@Entity 
@Table(name = "nim_subscription") 
public class Subscription 

@ManyToMany(fetch = FetchType.EAGER) 
@JoinTable(name = "nim_subscription_magazines", 
     joinColumns = @JoinColumn(name = "subscription_id"), 
     inverseJoinColumns = @JoinColumn(name = "magazine_id") 
) 
private List<Magazine> magazines; 

終於

@Entity 
@Table(name = "nim_magazine") 
public class Magazine 

這最後一個是一個查找表漂亮多了。

現在我正在測試使用DWR,因爲我找不到更好的方法來快速測試,到目前爲止沒有堆棧跟蹤也沒有顯示sql,即使hibernate有setShowSql(true)。我只得到這個消息:

2300777 [http-bio-9090-exec-4] WARN o.d.dwrp.BaseCallMarshaller - --Erroring: batchId[2] message[java.lang.NullPointerException] 

所以我的問題是:

  1. 我在做什麼錯?
  2. 如何測試/調試規格和/或謂詞比dwr更好,所以我可以得到堆棧跟蹤等?

編輯


一旦有所動作,JUnit測試類我得到下面的堆棧跟蹤:

java.lang.NullPointerException 
at org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.isNodeAcceptable(InLogicOperatorNode.java:99) 
at org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.initialize(InLogicOperatorNode.java:79) 
at org.hibernate.hql.internal.ast.HqlSqlWalker.prepareLogicOperator(HqlSqlWalker.java:1224) 
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4242) 
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1947) 
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:794) 
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:595) 
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:299) 
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:247) 
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:248) 
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:183) 
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136) 
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:105) 
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80) 
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:168) 
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:219) 
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:197) 
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1736) 
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:452) 
at org.hibernate.ejb.criteria.CriteriaQueryCompiler.compile(CriteriaQueryCompiler.java:221) 
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:587) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:289) 
at com.sun.proxy.$Proxy109.createQuery(Unknown Source) 
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:491) 
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:342) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:405) 
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:390) 
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:344) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) 
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:266) 
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) 
at com.sun.proxy.$Proxy153.findAll(Unknown Source) 
at test.nimchip.repository.FileRepositoryTest.testVictimizationFetch(FileRepositoryTest.java:118) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72) 
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81) 
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:60) 
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162) 
at org.junit.runners.Suite.runChild(Suite.java:127) 
at org.junit.runners.Suite.runChild(Suite.java:26) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

回答

0

我總是發現的標準API非常麻煩使用和it may generate horrible SQL statements even for trivial joins

試試這個的HQL查詢,而不是:

select f 
from File f 
inner join f.magazines file_magazine 
where exists (
    select s 
    from Subscription s 
    inner join s.magazines subscr_magazine 
    where s.id = :subscription_id and subscr_magazine.id = file_magazine.id 
) 

雖然你也可以檢查any/some/member of,這些表達式可能導致非常複雜的SQL查詢。嘗試建議的子選擇,看看它是怎麼回事。

我不知道,如果這個工程,但你還可以額外加入條款使用

select f 
from File f 
inner join f.magazines file_magazine 
where exists (
    select s 
    from Subscription s 
    inner join s.magazines subscr_magazine with subscr_magazine.id = file_magazine.id 
    where s.id = :subscription_id 
) 

用於記錄人SQL與參數查詢一起,你可以在你的應用程序數據源的前set up a datasurce-proxy

+0

我碰巧同意你的條件查詢評論,並且很喜歡使用HQL或JPQL,但我被指示使用謂詞來做這件事,因爲它提高了可重用性等等。我會研究一下我可以用你的建議做什麼。謝謝! – Nimchip 2014-11-03 14:38:28

+0

條件查詢對於動態過濾用例很有用,甚至類型安全屬性引用的優點也不會超越HQL表現力。即使我自己寫了標準查詢也很難理解。過了一段時間,我花了一些時間來解讀它們。生成的SQL根本不直觀。 – 2014-11-04 21:43:27