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。

解法:

  1. 使用BigInteger作为return类型

    @Query(value = "select distinct(oid) from unit", nativeQuery = true) List<BigInteger> testMethod();

    然后如下设置变量。
    Long variable = bigIntegerValue.longValue();

  2. 使用 String 作为 return 类型并转换为 Long

    @Query(value = "select distinct(oid) from unit", nativeQuery = true) List<String> testMethod();

    然后将值设置为

    Long variable = Long.valueOf(stringValue);

  3. 将数据库列类型更改为Integer/Number。

  4. 实体 对象获取值。

    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>