2011-07-04 17 views
8

Próbuję uzyskać następujące NamedQuery pracować:Hibernate: Nie można użyć nazwanego parametru dla OFFSET i LIMIT?

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

Problemem jest to, że powoduje to Hibernate wybuchnąć z poniższego śladu stosu po starcie serwera:

[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) 
(...) 

po pewnym badaniu i-błąd stwierdziłam, że zastąpienie ": offset" i ": limit" wartościami literowymi (odpowiednio 0 i 10) działało bez zarzutu. Czy istnieje ku temu powód i czy istnieje sposób, aby te parametry zadziałały w moim zapytaniu?

Widziałem kilka innych przykładów, które używają parametrów pozycjonowanych do dynamicznego ustawiania wartości przesunięcia i wartości granicznej w nazwanym zapytaniu, ale wolałbym, aby mój kod nie przerodził się w gromadę nieczytelnych bzdur. Nazwane parametry miały pozbyć się tego rodzaju kodu śmieciowego.

Odpowiedz

17

Hibernate ma specjalny interfejs API do określania tych pojęć w czasie wykonywania. Spróbuj tego:

@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(); 

Chyba powód to zrobić w ten sposób jest to, że producenci baz danych są bardzo zróżnicowane, w jaki sposób i gdzie w zapytaniu SQL te pojęcia są określone, więc nie jest to rozsądne, aby wybrać jednego formatu na inny, oraz zbyt trudne, aby spróbować przekonwertować między nimi.

W ten sposób implementacja dialektu dokładnie wie, co należy zrobić, i może to zrobić.

+3

Dzięki, ta metoda działa. Nie jestem pewien, czy całkowicie zgadzam się z powodem, dla którego jest oczywiste. Słowa kluczowe "OFFSET" i "LIMIT" są częścią specyfikacji EJBQL. A jeśli są w specyfikacji, powinny być wspierane jako takie. Co więcej, jeśli wsparcie dla nich miało zostać zniesione, powinno zostać całkowicie odrzucone, aby nawet użycie literalnych wartości w zapytaniu zakończyło się niepowodzeniem. Obecny stan rzeczy, w którym wartości dosłowne działają, a sparametryzowane wartości nie są, moim zdaniem, błędem. – aroth

+0

uczciwy komentarz - usunięto "oczywiste" z wpisu – Bohemian

+0

@aroth: to też mi się przydarzyło, ale tym razem jest to wartość ciągu znaków. Działa to dobrze, jeśli zastąpię parametr twardą wartością ... Sądzę, że za tym faktem kryje się inny błąd –

Powiązane problemy