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
Filter child object in Spring Data Query
提问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 PlaylistRepository
interface:
你所要做的就是在你的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 规范,您将:
- Enable your
PlaylistRepository
to use JPA Specifications - Write the
Specification
as a reusable method - Make use of the
Specification
as the query
- 使您
PlaylistRepository
能够使用 JPA 规范 - 将 编写
Specification
为可重用的方法 - 使用
Specification
作为查询
Here are the details.
这是详细信息。
1. Implement JpaSpecificationExecutor
1. 实施 JpaSpecificationExecutor
Update PlaylistRepository
to 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 join
s) is similar to using JOIN
in SQL. Here, we are joining on the fields of classes, instead of on columns of tables.
Using root.join
(以及后续的join
s)类似于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!
希望这可以帮助!