2011-07-04 70 views
8

我試圖得到以下NamedQuery工作:Hibernate:不能使用OFFSET和LIMIT的命名參數嗎?

@NamedQuery(name="MyEntity.findByUser", query="SELECT m FROM MyEntity m WHERE m.owner = :user OFFSET :offset LIMIT :limit") 

的問題是,這導致Hibernate與在服務器啓動時以下堆棧跟蹤爆炸:

[INFO] [talledLocalContainer] java.lang.NullPointerException 
[INFO] [talledLocalContainer] at org.hibernate.hql.ast.ParameterTranslationsImpl.getNamedParameterExpectedType(ParameterTranslationsImpl.java:63) 
[INFO] [talledLocalContainer] at org.hibernate.engine.query.HQLQueryPlan.buildParameterMetadata(HQLQueryPlan.java:296) 
[INFO] [talledLocalContainer] at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:97) 
[INFO] [talledLocalContainer] at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56) 
[INFO] [talledLocalContainer] at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72) 
[INFO] [talledLocalContainer] at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:400) 
[INFO] [talledLocalContainer] at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:351) 
[INFO] [talledLocalContainer] at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1291) 
[INFO] [talledLocalContainer] at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:713) 
[INFO] [talledLocalContainer] at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:121) 
[INFO] [talledLocalContainer] at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83) 
[INFO] [talledLocalContainer] at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:60) 
(...) 

一些試驗後 - 和 - 錯誤我發現用文字值(分別爲0和10)替換「:偏移」和「:限制」工作正常。是否有這樣的原因,並且有沒有辦法讓命名參數在我的查詢中工作?

我見過其他一些使用定位參數來動態設置指定查詢中的偏移量和限制值的示例,但我寧願不將我的代碼退化爲一堆無法讀取的廢話query.setParameter(1, "someValue");。命名的參數應該去掉那種垃圾代碼。

回答

17

Hibernate有一個特殊的API用於在運行時指定這些概念。試試這個:

@NamedQuery(name="MyEntity.findByUser", 
    query="SELECT m FROM MyEntity m WHERE m.owner = :user") // don't put OFFSET or LIMIT here 

... 

entityManager.createNamedQuery("MyEntity.findByUser") 
.setFirstResult(20) // equivalent to OFFSET 
.setMaxResults(5) // equivalent to LIMIT 
.getResultList(); 

我想這是做這種方式的原因是,數據庫廠商差異很大的方式和位置在SQL查詢中指定了這些概念,所以它不是合理的選擇一個格式而上,太難以嘗試在它們之間進行轉換。

這樣,方言實現清楚地知道需要做什麼,然後才能做到。

+3

謝謝,該方法的作品。但不確定我完全同意爲什麼顯而易見的原因。 'OFFSET'和'LIMIT'關鍵字是EJBQL規範的一部分。如果他們在規範中,他們應該受到支持。而且,如果對它們的支持被丟棄,它應該完全被丟棄,這樣即使在查詢中使用文字值也會失敗。在我看來,字面值工作和參數化值的東西的當前狀態不是一個錯誤。 – aroth

+0

公平的評論 - 從帖子中刪除「明顯」 – Bohemian

+0

@aroth:這也發生在我身上,但這次它是一個字符串參數值。它工作正常,如果我用硬值替換參數...我想這背後有其他錯誤 –