2011-07-04 125 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:这也发生在我身上,但这次它是一个字符串参数值。它工作正常,如果我用硬值替换参数...我想这背后有其他错误 –