Spring Data JPA 中的错误:Spring Data returns List<BigInteger> 而不是 List<Long>
Bug in Spring Data JPA: Spring Data returns List<BigInteger> instead of List<Long>
我在 spring-data:
上实现了 DAO
public interface TestDataRepository extends CrudRepository<DpConfigData, Long> {
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
List<Long> testMethod();
}
并进行单元测试以测试提到的 DAO:
@Test
public void test(){
List<Long> testData = dpConfigDataEntityDataRepository.testMethod();
for (Long oid:testData){
System.out.print(oid);
}
}
运行 测试给出奇怪的结果 - List<Long> testData
在运行时由 BigInteger 实例填充,而不是 Long。结果我得到 ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long
JPA 实现 - 休眠。
作为数据库,我使用 PostgreSQL,unit.oid
字段在数据库层上具有 BigInt 类型。
它在获取整个单元的情况下被映射到 Long,但是由于自定义查询 "select distinct ..." 出了点问题,它被映射到 BigInteger。
那么,我的问题是:这种奇怪行为的原因是什么?
如何以优雅的方式solve/workaround?
postgresql 中的 BigInt 映射到 BigInteger,因为它是无符号的
我认为最好的选择是将 JPA 对象中的 oid 从 Long 更改为 BigInteger
最后我通过在 "service" 图层上手动映射解决了这个问题。
例子(伪代码):
public interface TestDataRepository extends CrudRepository<DpConfigData, Long> {
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
List<Object> testMethod();
}
}
然后在服务层我做手动映射:
public class TestServiceImpl extends TestService {
pulic List<Object> testMethod(){
List<Object> rawList = testDataRepository.testMethod();
List<Object> resultList = new ArrayList(rawList.size());
for(Object rw:rawList){
resultList.add(Long.valueOf(String.valueOf(rw)));
}
return resultList;
}
}
这是 Spring 数据 JPA 的问题。
如果在 DB 中数据类型定义为 BigInteger 并且在 JPA 查询中我们尝试获取 Long 那么它不会给出任何错误,但它在 Long 数据类型中将值设置为 BigInteger。
解法:
使用BigInteger作为return类型
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
List<BigInteger> testMethod();
然后如下设置变量。
Long variable = bigIntegerValue.longValue();
使用 String 作为 return 类型并转换为 Long
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
List<String> testMethod();
然后将值设置为
Long variable = Long.valueOf(stringValue);
将数据库列类型更改为Integer/Number。
从 实体 对象获取值。
Long variable = dpConfigData.getOid();
其中 dpConfigData
是实体对象 (DpConfigData.class)
您可以使用 JPQL 进行尝试,如下所示:
public interface TestDataRepository extends
JpaRepository<DpConfigData, Long> {
@Query(value = "select distinct(u.oid) from unit u")
List<Long> testMethod();
}
只需确保您的实体对象对于给定属性也应具有相同的 Long 数据类型。
这个问题似乎在 2.1.8 版本中得到了解决
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
我在 spring-data:
上实现了 DAOpublic interface TestDataRepository extends CrudRepository<DpConfigData, Long> {
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
List<Long> testMethod();
}
并进行单元测试以测试提到的 DAO:
@Test
public void test(){
List<Long> testData = dpConfigDataEntityDataRepository.testMethod();
for (Long oid:testData){
System.out.print(oid);
}
}
运行 测试给出奇怪的结果 - List<Long> testData
在运行时由 BigInteger 实例填充,而不是 Long。结果我得到 ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long
JPA 实现 - 休眠。
作为数据库,我使用 PostgreSQL,unit.oid
字段在数据库层上具有 BigInt 类型。
它在获取整个单元的情况下被映射到 Long,但是由于自定义查询 "select distinct ..." 出了点问题,它被映射到 BigInteger。
那么,我的问题是:这种奇怪行为的原因是什么? 如何以优雅的方式solve/workaround?
postgresql 中的 BigInt 映射到 BigInteger,因为它是无符号的
我认为最好的选择是将 JPA 对象中的 oid 从 Long 更改为 BigInteger
最后我通过在 "service" 图层上手动映射解决了这个问题。 例子(伪代码):
public interface TestDataRepository extends CrudRepository<DpConfigData, Long> {
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
List<Object> testMethod();
}
}
然后在服务层我做手动映射:
public class TestServiceImpl extends TestService {
pulic List<Object> testMethod(){
List<Object> rawList = testDataRepository.testMethod();
List<Object> resultList = new ArrayList(rawList.size());
for(Object rw:rawList){
resultList.add(Long.valueOf(String.valueOf(rw)));
}
return resultList;
}
}
这是 Spring 数据 JPA 的问题。 如果在 DB 中数据类型定义为 BigInteger 并且在 JPA 查询中我们尝试获取 Long 那么它不会给出任何错误,但它在 Long 数据类型中将值设置为 BigInteger。
解法:
使用BigInteger作为return类型
@Query(value = "select distinct(oid) from unit", nativeQuery = true) List<BigInteger> testMethod();
然后如下设置变量。
Long variable = bigIntegerValue.longValue();
使用 String 作为 return 类型并转换为 Long
@Query(value = "select distinct(oid) from unit", nativeQuery = true) List<String> testMethod();
然后将值设置为
Long variable = Long.valueOf(stringValue);
将数据库列类型更改为Integer/Number。
从 实体 对象获取值。
Long variable = dpConfigData.getOid();
其中
dpConfigData
是实体对象 (DpConfigData.class)
您可以使用 JPQL 进行尝试,如下所示:
public interface TestDataRepository extends
JpaRepository<DpConfigData, Long> {
@Query(value = "select distinct(u.oid) from unit u")
List<Long> testMethod();
}
只需确保您的实体对象对于给定属性也应具有相同的 Long 数据类型。
这个问题似乎在 2.1.8 版本中得到了解决
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>