Hibernate: Не можете использовать именованный параметр для OFFSET и LIMIT? - PullRequest
9 голосов
/ 04 июля 2011

Я пытаюсь заставить работать 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)
(...)

После некоторых проб и ошибок я обнаружил, что замена «: offset» и «: limit» литеральными значениями (0 и 10 соответственно) работала нормально. Есть ли причина для этого, и есть ли способ заставить именованные параметры работать в моем запросе?

Я видел несколько других примеров, в которых позиционированные параметры используются для динамической установки значений смещения и пределов в именованном запросе, но я бы не хотел, чтобы мой код выродился в кучу нечитаемых query.setParameter(1, "someValue"); глупостей. Именованные параметры должны были избавиться от такого рода мусорного кода.

1 Ответ

20 голосов
/ 04 июля 2011

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-запросе указываются эти концепции, поэтому нецелесообразно выбирать один формат из другогои слишком трудно пытаться конвертировать между ними.

Таким образом, реализация диалекта четко знает, что нужно сделать, и может сделать это.

...