在Spring Data Query中过滤子对象

Mak*_*sim 13 java spring spring-data spring-data-jpa

我有以下域模型:

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
}
Run Code Online (Sandbox Code Playgroud)

我的存储库:

public interface PlaylistRepository extends JpaRepository<Playlist, Long> {
   List<Playlist> findAll();
}
Run Code Online (Sandbox Code Playgroud)

现在,如何返回仅包含现有视频的播放列表,即如果分配给该播放列表项目的数据库中有三个视频,并且其中一个视频的isDeleted设置为true,那么我只需要获取两个项目.

ina*_*cao 14

您所要做的就是在您的PlaylistRepository界面上声明此方法:

List<Playlist> findByPlaylistItemsVideoIsDeleted(boolean isDeleted);
Run Code Online (Sandbox Code Playgroud)

并称之为:

playListRepository.findByPlaylistItemsVideoIsDeleted(false);
Run Code Online (Sandbox Code Playgroud)

这将返回所有未删除视频的播放列表.

  • 您能解释一下这是如何神奇地工作吗?对jpa有何描述? (2认同)

Dio*_*ans 5

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();
}
Run Code Online (Sandbox Code Playgroud)

甚至更好的方式:

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);
}
Run Code Online (Sandbox Code Playgroud)


Jac*_*raw 5

您可能已经解决了这个问题,但我想我会贡献这个,希望它可以帮助您或访问此页面的任何其他人。

使用 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> {

}
Run Code Online (Sandbox Code Playgroud)

2. 创建 Specification

创建一个带有静态方法的类,用于创建可重用的 Specification.

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);
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

Using root.join(和后续的joins)类似于JOIN在 SQL 中使用。在这里,我们加入的是 classes字段,而不是表的列。

3.发出查询

我不知道您打算如何发出查询,但以下是如何在“服务”类中完成的示例:

@Service
public class PlaylistService {

    @Autowired
    private PlaylistRepository playlistRepository;

    public List<Playlist> findPlaylistsWithExistingVideos() {

        Specification<Playlist> spec = PlaylistSpecifications.hasExistingVideos();
        return playlistRepository.findAll(spec);
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!