我有一个奇怪的问题,我无法弄清楚它为什么会发生。我确定我做错了,因为这是我第一次使用数据投影而且我从来没有使用过DTO这样的问题。
我有一个SELECT状态员返回各种数据类型的某些列。我有一个接口,我将其传递给JPA存储库,以便它可以进行接口映射。但是,不是根据列名映射结果(例如,' 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语句中列的顺序映射到接口中按字母顺序排序的方法。
所以:
SELECT date_of_order, accountnumber, tracking_id
结果:
getAccountNumber() -> date_of_order
getDateOfOrder() -> accountnumber
getTrackingId() -> tracking_id
它会以这种方式不断回归,所以它不是一个短暂的问题。
作为临时解决方法,我在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所引入的。
答案 0 :(得分:4)
不确定这是否是正确的解决方案,因为它只适合80%的描述。但评论太长了。所以我们走了。
我认为你误解了@ osamayaccoub或文档。你的房产名称没问题。但是select中的列应该与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\" "
这可能不起作用,因为您正在使用has a bug的Hibernate版本,因为它将所有内容转换为小写。
所以你应该升级到最新的Hibernate版本5.3.13,它已经解决了这个问题。
这个错误修复有趣的可能会打破没有双引号的版本。 但是对this PR Spring Data JPA issue,它应该再次使用this。
我不理解的部分是,为什么使用列顺序分配内容。
答案 1 :(得分:2)
我有同样的问题,我通过按字母顺序查询查询列来解决。
在你的情况下:
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);
}
所以你会得到:
getAccountNumber() - &gt;帐号 getDateOfOrder() - &gt; date_of_order getTrackingId() - &gt; TRACKING_ID
答案 2 :(得分:-2)
Hibernate 按字母顺序对查询进行排序,因此您必须将选项更改为:“SELECT a.accountnumber, o.date_of_order, t.tracking_id
...”并且界面的getter应遵循相同的字母顺序< /强>