[英]Hibernate pagination not working when using native queries (Named query exists but its result type is not compatible)
我的orm.xml
中有兩個命名的本機查詢,一個用於檢索數據,一個用於為我的分頁計數:
<named-native-query name="Person.findPeople.count">
<query>select count(*) from
from person
</query>
</named-native-query>
<named-native-query name="Person.findPeople">
<query>select first_name, last_name
from person
</query>
</named-native-query>
為了加載這些數據,我有一個 Spring Data Repository,它加載數據的投影(我的實際代碼比提供的示例更復雜):
@Query(nativeQuery = true)
fun findPeople(pageable: Pageable): Page<PersonFirstName>
現在,當我執行上面的代碼時,我收到了一個錯誤:
Caused by: java.lang.IllegalArgumentException: Named query exists but its result type is not compatible
at org.hibernate.internal.AbstractSharedSessionContract.resultClassChecking(AbstractSharedSessionContract.java:984) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
at org.hibernate.internal.AbstractSharedSessionContract.createNativeQuery(AbstractSharedSessionContract.java:942) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
at org.hibernate.internal.AbstractSharedSessionContract.buildQueryFromName(AbstractSharedSessionContract.java:920) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
這是由 Hibernate 引起的,它不想將本機計數查詢映射到 Long。 我已將orm.xml
中的named-native-query
更改為named-query
,這確實有效,但我無法在實際代碼中使用它。
重現該問題的完整代碼如下(也可以在 Github 上找到):
@SpringBootApplication
class HibernateBugApplication : ApplicationRunner {
@Autowired
lateinit var personRepository: PersonRepository
override fun run(args: ApplicationArguments?) {
personRepository.saveAll(listOf(Person("a", "a1"), Person("b", "b1"), Person("c", "c1")))
personRepository.findPeople(Pageable.ofSize(2))
}
}
@Repository
interface PersonRepository : JpaRepository<Person, Long> {
@Query(nativeQuery = true)
fun findPeople(pageable: Pageable): Page<PersonFirstName>
}
interface PersonFirstName {
fun getName(): String
}
@Entity
class Person(
val firstName: String,
val lastName: String,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null
)
和orm.xml
:
<!-- This query works, but the named version does not.
<named-query name="Person.findPeople.count">
<query>select count(p) from Person p</query>
</named-query>
-->
<named-native-query name="Person.findPeople.count">
<query>select count(*) from
from person
</query>
</named-native-query>
<named-native-query name="Person.findPeople">
<query>select first_name, last_name
from person
</query>
</named-native-query>
我幾乎認為這可能是 Hibernate 中的一個錯誤,但在報告它之前我很想知道我的配置中是否沒有遺漏一些東西。
我正在使用 Spring 2.7.1、Hibernate 5.6.9 和 Kotlin 1.7.0
與解決方案一樣,您需要為 count 本機查詢指定返回類型。
它可以通過sql-result-set-mapping來完成。
JPA 版本 1.0 和 2.0
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_2_0.xsd ">
<named-native-query name="Person.findPeople.count" result-set-mapping="cntColumnResult">
<query>select count(*) cnt from person</query>
</named-native-query>
<named-native-query name="Person.findPeople">
<query>select first_name, last_name from person</query>
</named-native-query>
<sql-result-set-mapping name="cntColumnResult">
<column-result name="cnt"/>
</sql-result-set-mapping>
</entity-mappings>
JPA 2.1 版
將映射配置前移到entity-mappings version="2.1"
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd">
<named-native-query name="Person.findPeople.count" result-set-mapping="cntColumnResult">
<query>select count(*) cnt from person</query>
</named-native-query>
<named-native-query name="Person.findPeople">
<query>select first_name, last_name from person</query>
</named-native-query>
<sql-result-set-mapping name="cntColumnResult">
<column-result name="cnt" class="java.lang.Long"/>
</sql-result-set-mapping>
</entity-mappings>
或者
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd">
<named-native-query name="Person.findPeople.count" result-set-mapping="cntConstructorResult">
<query>select count(*) cnt from person</query>
</named-native-query>
<named-native-query name="Person.findPeople">
<query>select first_name, last_name from person</query>
</named-native-query>
<sql-result-set-mapping name="cntConstructorResult">
<constructor-result target-class="java.lang.Long">
<column name="cnt" class="java.lang.Long"/>
</constructor-result>
</sql-result-set-mapping>
</entity-mappings>
我認為這是spring-data-jpa中的一個缺陷或可能是一個新功能。 有問題的源代碼行。
countQuery = em.createNamedQuery(countQueryName, Long.class);
如果在查詢創建期間不會傳遞Long.class
類型,我們將不需要在映射配置中為計數查詢指定確切的類型。 在這種情況下,Hibernate 運行良好。
可能的解決方案示例為原生而不是鍵入創建原始查詢:
Query query = getQueryMethod().isNativeQuery()
? em.createNativeQuery(queryString)
: em.createQuery(queryString, Long.class);
因此,如果您有時間,請為 spring-data-jpa 項目發布一個新問題,這樣一個小的查詢更正將大大簡化映射配置。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.