web-dev-qa-db-ja.com

Spring Data Queryで子オブジェクトをフィルタリングする

次のドメインモデルがあります。

Playlist-> List<PlaylistItem>-> Video

@Entity
class Playlist{
   // id, name, etc
   List<PlaylistItem> playlistItems;
   // getters and setters
}


@Entity
class PlaylistItem{
   // id, name, etc.
   Video video;
   // getters and setters
}


@Entity
class Video{
   // id, name, etc.
   boolean isDeleted;
   // getters and setters
}

そして私のリポジトリ:

public interface PlaylistRepository extends JpaRepository<Playlist, Long> {
   List<Playlist> findAll();
}

ここで、既存のビデオのみを含む再生リストを返す方法を示します。つまり、データベースに3つのビデオがその再生リストアイテムに割り当てられており、それらのビデオの1つにisDeletedがtrueに設定されている場合、代わりに2つのアイテムのみを取得する必要があります。

14
Maksim

あなたがしなければならないすべてはあなたのPlaylistRepositoryインターフェースでこのメソッドを宣言することです:

List<Playlist> findByPlaylistItemsVideoIsDeleted(boolean isDeleted);

次のように呼び出します。

playListRepository.findByPlaylistItemsVideoIsDeleted(false);

削除されていない動画を含むすべての再生リストが返されます。

15
inafalcao

Maksim、次のように@ query注釈を使用できます。

public interface PlaylistRepository extends JpaRepository<Playlist, Long> {
   @Query("select playlist from Playlist playlist 
           fetch join playlist.playlistItems itens
           fetch join itens.video as video
           where video.isDeleted = false")
   List<Playlist> findAll();
}

またはさらに良い方法:

public interface PlaylistRepository extends JpaRepository<Playlist, Long> {
   @Query("select playlist from Playlist playlist 
           fetch join playlist.playlistItems itens
           fetch join itens.video as video
           where video.isDeleted = :hasVideo ")
   List<Playlist> findPlayList(@Param("hasVideo") boolean hasVideo);
}
5
Diogo Calazans

Springデータ仕様を調べることができます。それらを使用するには、repository.findAll(s);を呼び出します。

仕様を使用すると、追加するフィルターを含め、クエリに任意の条件を追加できます。仕様のもう1つの良い点は、タイプセーフであるということです。こちらをご覧ください:

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#specifications

3

あなたはすでにこの問題を解決しているかもしれませんが、あなたやこのページにアクセスしている他の人に役立つことを期待して、私はこれを寄稿すると思いました。

Spring JPA仕様を使用して、次のことを行います。

  1. PlaylistRepositoryがJPA仕様を使用できるようにします
  2. Specificationを再利用可能なメソッドとして記述する
  3. Specificationをクエリとして使用する

詳細はこちら。

1.実装JpaSpecificationExecutor

PlaylistRepositoryを実装するためにJpaSpecificationExecutorを更新します。これにより、find*パラメータを受け入れるSpecification<T>メソッドがPlaylistRepositoryに追加されます。

public interface PlaylistRepository extends JpaRepository<Playlist, Long>, 
            JpaSpecificationExecutor<Playlist> {

}

2. Specificationを作成します

reusableSpecificationの作成に使用する静的メソッドでクラスを作成します。

public final class PlaylistSpecifications {

    private PlaylistSpecifications() {}

    public static Specification<Playlist> hasExistingVideos() {
        return (root, query, cb) -> {
            return cb.equal(root.join("playlistItems").join("video")
                    .get("isDeleted"), false);
        };
    }
}

root.join(および後続のjoins)の使用は、SQLでのJOINの使用に似ています。ここでは、テーブルの列ではなくクラスのフィールドで結合しています。

3.クエリを発行する

クエリをどのように発行するかはわかりませんが、以下は「サービス」クラスでどのように実行できるかの例です。

@Service
public class PlaylistService {

    @Autowired
    private PlaylistRepository playlistRepository;

    public List<Playlist> findPlaylistsWithExistingVideos() {

        Specification<Playlist> spec = PlaylistSpecifications.hasExistingVideos();
        return playlistRepository.findAll(spec);
    }
}

お役に立てれば!

1
Jack Straw