在我的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数据存储库,它加载数据的投影(我的实际代码比提供的示例更复杂):

@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引起的,Hibernate不想将本机计数查询映射到Long.我把orm.xml中的named-native-query改成了named-query,这确实管用,但我无法在实际代码中使用它.

再现问题的完整代码如下(and can also be found on 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中的一个bug,但在报告之前,我想知道我的配置中是否遗漏了什么.

我使用的是Spring 2.7.1、Hibernate 5.6.9和Kotlin 1.7.0

推荐答案

与解决方案类似,您需要为count本机查询指定返回类型.

<?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 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中的一个缺陷或可能是一个新特性.Problematic source code line

countQuery = em.createNamedQuery(countQueryName, Long.class);

如果在查询创建期间不传递Long.class类型,我们将不需要在映射配置中为count查询指定确切的类型.Hibernate在这种情况下运行良好.

        Query query = getQueryMethod().isNativeQuery()
                ? em.createNativeQuery(queryString)
                : em.createQuery(queryString, Long.class);


因此,如果您有时间,请发布spring data jpa项目的新版本,这样一个小的查询更正将大大简化映射配置.

Java相关问答推荐

内容处置 destruct 了PSP请求

Java -使用空比较或instanceof?

Jooq隐式地将bigint转换为数字,并且索引不起作用

使用log 4j2格式的Hibernate 显示SQL日志(log)

Java 21虚拟线程会解决转向react 式单线程框架的主要原因吗?

Java JAR环境(JRE)是否支持模块?

为什么Java中的两个日期有差异?

Intellij显示项目语言级别最高为12,尽管有java版本17 SDK

springboot start loge change

按属性值从流中筛选出重复项

如何对多个字段进行分组和排序?

匹配一组字符或另一组字符

Java中不兼容的泛型类型

当b是一个字节并且在Java中值为-1时,为什么b>;>;>;1总是等于-1?

为什么StandardOpenOption.CREATE不能通过Ubuntu在中小企业上运行?

是否有一个Java Future实现可以在池繁忙时在调用者线程中执行?

JavaFX:无论何时显示应用程序,如何更改组件/ node 位置?

何时调用密封层次 struct 的switch 中的默认情况

如何在Spring Boot Auth服务器上正确配置CORS?

";重复键的值提示唯一约束«;livre_genre_pkey»";例外