Spring JPA 具有 native 查询和数据投影,将错误的列映射到投影接口(interface)中

标签 spring hibernate spring-data-jpa

我遇到了一个奇怪的问题,我不明白为什么会发生。我确信我做错了什么,因为这是我第一次使用数据投影,并且在使用 DTO 时从未遇到过此类问题。

我几乎有一个 SELECT 语句,它返回各种数据类型的某些列。我有一个接口(interface),我将其传递到 JPA 存储库,以便它可以执行接口(interface)映射。但它不是根据列名称映射结果(例如 'accountnum' -> getAccountnumber() ),而是按字母顺序映射列。因此,如果“date_of_order”是 SELECT 语句中的第一个,则其值将由 getAccountnumber() 返回。 .

我有一个看起来像这样的投影界面:

public interface FlatSearchResult {
    String getAccountnumber();
    UUID getTrackingId;
    Date getDateOfOrder;
}

我的模型有三个表,如下所示:

ACCOUNT
  - account_id : uuid (pkey)
  - accountnumber : string
ORDERS
  - order_id : uuid (pkey)
  - date_of_order : timestamp
  - account_id : uuid (fkey)
TRACKING
  - tracking_id : uuid (pkey)
  - order_id : uuid (fkey)

每个表中还有其他列,但它们不相关。

我有一个使用简单查询定义的存储库:

public interface OrderTrackingRepository extends JpaRepository<Account, UUID> {
  @Query( nativeQuery = true,
          value = "SELECT o.date_of_order, a.accountnumber, t.tracking_id " +
                  "FROM account as a " +
                  "INNER JOIN orders as o USING (account_id) " +
                  "INNER JOIN tracking as t USING (tracking_id) " +
                  "WHERE a.accountnumber = :acctnum")
  <T> Collection<T> findOrderInfoForAccount(@Param("acctnum") acctNumber, Class<T> type);
}

当我调用此方法时,查询将返回正确的行。但它不是使用列名称映射(例如 date_of_order 到 getDateOfOrder() ),而是根据 SELECT 语句中的列顺序映射到接口(interface)中按字母顺序排列的方法。

所以:

SELECT date_of_order, accountnumber, tracking_id

结果:

getAccountNumber() -> date_of_order
getDateOfOrder() -> accountnumber
getTrackingId() -> tracking_id

它会始终以这种方式返回,因此这不是一个暂时性问题。

作为临时解决方法,我对 SELECT 语句中的列进行了重新排序。但我宁愿不必这样做,因为这就像迭代结果集并依赖列位置,这让我感到不安......

如何让 Spring JPA 从结果集映射到我的界面?我是否需要用一些东西来注释我的投影接口(interface)的方法来告诉 Spring 它所引用的列名称?

我的数据库是 Postgres。我正在使用 Spring 5.0.2.RELEASE 和 Spring-Boot 2.0.0.M7。如果需要,我可以将其中任何一个调整为较新的版本,但不能调整为较旧的版本。我使用 C3P0 0.9.5.2 作为连接池,并使用 postgres-9.2-1002.jdbc4。我的所有其他依赖项(hibernate 等)都是这个版本的 Spring-Boot 引入的。

最佳答案

不确定这是否是正确的解决方案,因为它只符合描述的 80%。但评论太长了。那么我们开始吧。

我认为您误解了@osamayaccoub 或文档。你的特性名称很好。但您选择的列应符合 java 约定。

因此,解决这个问题的第一次尝试是

value = "SELECT o.date_of_order as dateOfOrder, a.accountnumber as accountNumber, t.tracking_id as trackingId "

注意:这可能确实有效,但稍后可能会崩溃,所以请继续阅读,即使它确实有效

但是 Postgres 会将所有非双引号的内容转换为小写(Oracle 和 MySql 执行类似的操作,尽管细节有所不同,尚不了解其他数据库)。所以你真的应该使用:

value = "SELECT o.date_of_order as \"dateOfOrder\", a.accountnumber as \"accountNumber\", t.tracking_id as \"trackingId\" "

这可能不起作用,因为您使用的 Hibernate 版本 has a bug因为它将所有内容都转换为小写。

因此您应该升级到最新的 Hibernate 版本 5.3.13,该版本已修复该问题。

有趣的是,这个错误修复可能会破坏没有双引号的版本。 但它应该再次与 this PR 一起工作。为此Spring Data JPA issue .

我不明白的部分是,为什么使用列顺序分配内容。

关于Spring JPA 具有 native 查询和数据投影,将错误的列映射到投影接口(interface)中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48726529/

相关文章:

针对休息应用程序的 Spring 设计模式推荐

java - Spring 馈送集成

spring - 我们如何从 Spring session 范围的 bean 中获取 bean 对象?

java - 如何在 Angular 应用程序上显示来自 springboot 的异常消息

java - 从投影列表中获取子实体时出现间歇性惰性异常

mysql - 带有 hibernate 的 Spring 数据 : multiple row insert in one-to-many entity without cascade

java - JPA 仅选择一列中的一个参数并将其放入字符串中

java - 使用映射实体映射对象

java - 在Java8中使用过滤器和映射提取数据库列数据

java - Spring 数据 JPA : Batch insert for nested entities