Hibernate:不能为OFFSET和LIMIT使用命名参数?

aro*_*oth 10 java hibernate ejbql named-parameters

我正在努力让以下NamedQuery工作:

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

问题是,这会导致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)
(...)
Run Code Online (Sandbox Code Playgroud)

经过一些反复试验后,我发现用文字值(分别为0和10)替换":offset"和":limit"工作正常.是否有这样的原因,有没有办法让命名参数在我的查询中工作?

我已经看到一些其他示例使用定位参数来动态设置命名查询中的偏移量和限制值,但我宁愿不让我的代码退化为一堆难以理解的query.setParameter(1, "someValue");废话.命名参数应该摆脱那种垃圾代码.

Boh*_*ian 21

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();
Run Code Online (Sandbox Code Playgroud)

我想这样做的原因是数据库供应商在SQL查询中指定这些概念的方式和位置方面存在很大差异,因此选择一种格式而不是另一种格式是不合理的,并且很难尝试在它们之间进行转换.

通过这种方式,方言实现清楚地知道需要做什么,然后可以做到.

  • 谢谢,这种方法有效.然而,不确定我完全同意显而易见的原因.`OFFSET`和`LIMIT`关键字是EJBQL规范的一部分.如果它们符合规范,那么它们应该得到支持.此外,如果要删除对它们的支持,则应该完全删除它,以便即使在查询中使用文字值也会失败.在我看来,文字值工作和参数化值的事物的当前状态不是错误. (4认同)