web-dev-qa-db-ja.com

Spring Data JPA:クエリは非エンティティオブジェクトまたはオブジェクトのリストをどのように返すことができますか?

私は私のプロジェクトでスプリングデータJPAを使用しています。私は何百万ものレコードで遊んでいます。さまざまなテーブルのデータをフェッチし、オブジェクトを作成してからUIにペイントする必要があるという要件があります。さて、これを私のSpringデータリポジトリで実現する方法。名前付きネイティブクエリで実現できることを読みました。

名前付きネイティブクエリがエンティティまたはエンティティのリストを返さない場合は、@ SqlResultSetMappingアノテーションを使用して、クエリ結果を正しい戻り値の型にマップできます。

しかし、@SqlResultSetMappingを使用しようとすると、別のentityResultを使用します。私が理解しているのは、クエリ結果をエンティティの結果セットに変換するだけですが、エンティティ以外のオブジェクトの結果セットが必要なことです。

@SqlResultSetMapping(
    name="studentPercentile",
    entities={
        @EntityResult(
           entityClass=CustomStudent.class,
              fields={
                  @FieldResult(name="id", column="ID"),
                  @FieldResult(name="firstName", column="FIRST_NAME"),
                   @FieldResult(name="lastName", column="LAST_NAME")
              }         
        )
   }
) 
@NamedNativeQuery(
    name="findStudentPercentile", 
    query="SELECT * FROM STUDENT", 
    resultSetMapping="studentPercentile")

上記の例では、学生のエンティティから別のpojo 'CustomStudent'に結果を取得しようとしていますが、これはエンティティではありません。 (この例はPOCの目的のためだけに実行しようとしていますが、実際のユースケースは非常に複雑で、複雑なクエリが異なる結果セットを返します)。

上記のユースケースを達成するには?リポジトリメソッドが非エンティティオブジェクトを返す名前クエリを使用する以外の方法はありますか?

33
DHRUV BANSAL

これに初めて出会ったとき、私は非常に驚きましたが、はい、@ SqlResultSetMappingを使用してクエリ結果をスカラーと管理対象エンティティにのみマッピングできます。

あなたができる最善の方法は、自動マッピングをスキップすることです。マッピングなしのクエリはList<Object[]>を返し、必要な方法でマッピングできます。

別のアプローチは、@ MappedSuperclassを使用することです。 @MappedSuperclass(この場合はCustomStudent)として示されているクラスは、@ SqlResultSetMappingで使用できます(ただし、100%ではありません)。ただし、継承階層を導入する必要があります。つまり、StudentエンティティはCustomStudentを拡張する必要があります。適切なOO設計からほとんどの時間を吸うでしょう。なぜなら、継承は少し人工的だからです...

24

次のようなことができます

@NamedQuery(name="findWhatever", query="SELECT new path.to.dto.MyDto(e.id, e.otherProperty) FROM Student e WHERE e.id = ?1")

その場合、MyDtoオブジェクトには、正しいフィールドで定義されたコンストラクター、つまり.

public MyDto(String id, String otherProperty) { this.id = id; this.otherProperty = otherProperty; }
24
tlavarea

JPA 2.1はどうですか ConstructorResult

@SqlResultSetMapping(
    name="studentPercentile",
    classes={
        @ConstructorResult(
            targetClass=CustomStudent.class,
            columns={
                @ColumnResult(name="ID"),
                @ColumnResult(name="FIRST_NAME"),
                @ColumnResult(name="LAST_NAME")
            }
        )
    }
)

@NamedNativeQuery(name="findStudentPercentile", query="SELECT * FROM STUDENT", resultSetMapping="studentPercentile")
18
Daimon