【问题标题】:Hibernate: Can't use a named parameter for OFFSET and LIMIT?Hibernate:不能为 OFFSET 和 LIMIT 使用命名参数?
【发布时间】:2011-07-04 01:26:19
【问题描述】:

我正在尝试让以下NamedQuery 工作:

@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)替换 ":offset" 和 ":limit" 效果很好。这是有原因的吗?有没有办法让命名参数在我的查询中起作用?

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

【问题讨论】:

    标签: java hibernate named-parameters ejbql


    【解决方案1】:

    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 查询中指定这些概念的方式和位置方面存在很大差异,因此选择一种格式而不是另一种格式是不合理的,而且很难尝试在两者之间进行转换他们。

    这样,方言实现就清楚知道需要做什么,然后就可以去做了。

    【讨论】:

    • 谢谢,该方法有效。但是,我不确定我是否完全同意显而易见的原因。 OFFSETLIMIT 关键字是 EJBQL 规范的一部分。如果它们在规范中,它们应该得到支持。此外,如果要删除对它们的支持,则应该完全删除它,以至于即使在查询中使用文字值也会失败。在我看来,文字值起作用而参数化值不起作用的当前状态是一个错误。
    • 公平评论 - 从帖子中删除“明显”
    • @aroth:这也发生在我身上,但这次是字符串参数值。如果我用硬值替换参数,它工作正常......我猜这个事实背后还有其他错误
    猜你喜欢
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    • 1970-01-01
    • 2011-07-27
    • 2020-08-19
    • 2012-08-25
    相关资源
    最近更新 更多