web-dev-qa-db-ja.com

Spring Data JPAのバグ:SpringDataはList <Long>ではなくList <BigInteger>を返します

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実行時に、LongではなくBigIntegerインスタンスが入力されます。その結果、次のようになりますClassCastException:Java.math.BigIntegerをJava.lang.Longにキャストできません

JPAの実装-休止状態。 DBとして私はPostgreSQLを使用しています、unit.oidフィールドはDBレイヤーでBigIntタイプです。ユニット全体をフェッチする場合はLongにマップされますが、「selectdistinct ...」としてカスタムクエリを使用すると、問題が発生し、BigIntegerにマップされます。

だから、私の質問:そのような奇妙な行動の原因は何ですか?エレガントな方法でそれを解決/回避する方法は?

16
Oleksandr_DJ

最後に、「サービス」レイヤーに手動でマッピングすることで、この問題を回避しました。例(擬似コード):

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;
    }
}
1
Oleksandr_DJ

これはSpringデータJPAの問題です。 DBでデータ型がBigIntegerとして定義されており、JPAクエリでLongとしてフェッチしようとすると、エラーは発生しませんが、Longデータ型ではBigIntegerとして値が設定されます。

解決策:

  1. BigIntegerを戻り値の型として使用します

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

    次に、変数を次のように設定します。
    Long variable = bigIntegerValue.longValue();

  2. Stringを戻り値の型として使用し、Longに変換します

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

    次に、値を次のように設定します

    Long variable = Long.valueOf(stringValue);

  3. DB列タイプを変更を整数/数値に変更します。

  4. エンティティオブジェクトから値を取得します。

    Long variable = dpConfigData.getOid();

    ここで、dpConfigDataはEntity(DpConfigData.class)のオブジェクトです。

6
TheSprinter

PostgresqlのBigIntは、署名されていないため、BigIntegerにマップされます

JPAオブジェクトでoidをLongからBigIntegerに変更するのが最善の選択肢だと思います

0
farrellmr

以下のようにJPQLを使用してこれを試すことができます。

public interface TestDataRepository extends 
JpaRepository<DpConfigData, Long> {
@Query(value = "select distinct(u.oid) from unit u")
   List<Long> testMethod();
  }

エンティティオブジェクトも、指定された属性に対して同じデータ型Longを持っている必要があることを確認してください。

0
Amber