簡體   English   中英

使用本機查詢時休眠分頁不起作用(命名查詢存在但其結果類型不兼容)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM