Java 在 Spring Data Query 中过滤子对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26684361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:03:20  来源:igfitidea点击:

Filter child object in Spring Data Query

javaspringspring-dataspring-data-jpa

提问by Maksim

I have a following domain model:

我有以下域模型:

Playlist-> List<PlaylistItem>-> Video

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
}

And my repository:

还有我的存储库:

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

Now, how do I return a playlist with only existing videos, ie, if there are three videos in the database assigned to that playlist item and one of those videos has isDeleted set to true, then I need to get only two items instead.

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

回答by Diogo Calazans

Maksim, you could use the @queryannotation like this :

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();
}

Or even better way :

或者更好的方法:

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);
}

回答by Michael Tontchev

You can look into Spring Data Specifications. You use them by calling repository.findAll(s);

您可以查看 Spring Data Specifications。您可以通过调用 repository.findAll(s); 来使用它们。

Specifications allow you add on arbitrary conditions to your query, including the filter you want to add. Another nice thing about Specifications is that they can be type-safe. See here:

规范允许您向查询添加任意条件,包括要添加的过滤器。规范的另一个好处是它们可以是类型安全的。看这里:

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

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

回答by inafalcao

All you have to do is declare this method on your PlaylistRepositoryinterface:

你所要做的就是在你的PlaylistRepository界面上声明这个方法:

List<Playlist> findByPlaylistItemsVideoIsDeleted(boolean isDeleted);

And call it like this:

并这样称呼它:

playListRepository.findByPlaylistItemsVideoIsDeleted(false);

That will return all playlist with videos that are not removed.

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

回答by Hyman Straw

You may have already resolved this issue, but I thought I would contribute this in hopes it might help you, or anyone else visiting this page.

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

Using Spring JPA Specifications, you would:

使用 Spring JPA 规范,您将:

  1. Enable your PlaylistRepositoryto use JPA Specifications
  2. Write the Specificationas a reusable method
  3. Make use of the Specificationas the query
  1. 使您PlaylistRepository能够使用 JPA 规范
  2. 将 编写Specification为可重用的方法
  3. 使用Specification作为查询

Here are the details.

这是详细信息。

1. Implement JpaSpecificationExecutor

1. 实施 JpaSpecificationExecutor

Update PlaylistRepositoryto implement JpaSpecificationExecutor. This adds find*methods that accept Specification<T>parameters to your PlaylistRepository.

更新PlaylistRepository以实施JpaSpecificationExecutor. 这会将find*接受Specification<T>参数的方法添加到您的PlaylistRepository.

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

}

2. Create the Specification

2. 创建 Specification

Create a class with a static method for use in creating a reusableSpecification.

创建一个带有静态方法的类,用于创建可重用的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);
        };
    }
}

Using root.join(and subsequent joins) is similar to using JOINin SQL. Here, we are joining on the fields of classes, instead of on columns of tables.

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

3. Issue the Query

3.发出查询

I don't know how you plan to issue your query, but below is an example of how it could be done in a "service" class:

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

@Service
public class PlaylistService {

    @Autowired
    private PlaylistRepository playlistRepository;

    public List<Playlist> findPlaylistsWithExistingVideos() {

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

Hope this helps!

希望这可以帮助!