我遇到了一个奇怪的问题,我不明白为什么会发生。我确信我做错了什么,因为这是我第一次使用数据投影,并且在使用 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/