带有本机查询和数据投影的Spring JPA,将错误的列映射到投影的接口

Rod*_*eas 8 spring hibernate spring-data-jpa

我有一个奇怪的问题,我不知道为什么会发生。我敢肯定我做错了,因为这是我第一次使用数据投影,而使用DTO从来没有这样的问题。

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

我有一个预计的界面,看起来像这样:

public interface FlatSearchResult {
    String getAccountnumber();
    UUID getTrackingId;
    Date getDateOfOrder;
}
Run Code Online (Sandbox Code Playgroud)

我的模型有三个这样的表:

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)
Run Code Online (Sandbox Code Playgroud)

这些表中的每个都有其他列,但是它们并不相关。

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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

所以:

SELECT date_of_order, accountnumber, tracking_id
Run Code Online (Sandbox Code Playgroud)

结果是:

getAccountNumber() -> date_of_order
getDateOfOrder() -> accountnumber
getTrackingId() -> tracking_id
Run Code Online (Sandbox Code Playgroud)

它会以这种方式持续返回,因此这不是暂时的问题。

作为临时的解决方法,我对SELECT语句中的列进行了重新排序。但是我宁愿不必这样做,因为这就像遍历结果集并依赖列位置一样,这让我有些抽搐。

如何获得Spring JPA将结果集映射到我的界面?我是否需要在投影接口的方法上添加注释,以告诉Spring它指的是什么列名?

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

tet*_*Arg 8

我遇到了同样的问题,我通过按字母顺序对查询列进行排序来解决。

在你的情况下:

public interface OrderTrackingRepository extends JpaRepository<Account, UUID> {
  @Query( nativeQuery = true,
          value = "SELECT a.accountnumber, o.date_of_order, 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);
}
Run Code Online (Sandbox Code Playgroud)

所以你会得到:

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


Jen*_*der 5

不确定这是否是正确的解决方案,因为它仅适合描述的80%。但是评论太久了。所以我们开始。

我认为您误解了@osamayaccoub或文档。您的财产名称可以。但是您选择的列应匹配Java约定。

因此,首先要解决的问题是

value = "SELECT o.date_of_order as dateOfOrder, a.accountnumber as accountNumber, t.tracking_id as trackingId "
Run Code Online (Sandbox Code Playgroud)

注意:这实际上可能有效,但可能会在以后中断,因此即使确实有效,也请继续阅读

但是Postgres会将所有未用双引号引起来的内容转换为小写(Oracle和MySql做类似的事情,尽管细节有所不同,尚不了解其他DB)。因此,您确实应该使用:

value = "SELECT o.date_of_order as \"dateOfOrder\", a.accountnumber as \"accountNumber\", t.tracking_id as \"trackingId\" "
Run Code Online (Sandbox Code Playgroud)

这可能不起作用,因为您使用的Hibernate版本存在一个错误,该错误会将所有内容都转换为小写。

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

有趣的是,此错误修复可能会破坏没有双引号的版本。但是,对于此Spring Data JPA问题,它应该可以与此PR再次配合使用。

我不明白的部分是,为什么要使用列顺序分配东西。