spring-boot - 带有规范的 Spring Data JPA @Query
问题描述
我需要创建一个 REST api。Api 允许用户在 URL 中提供动态搜索条件。例如,假设我有一个带有 Note_ID、NOTE_TEXT、STATUS、PERSON_ID 列的 NOTES 表。这张表是用来记录每个人的。
现在我希望我的 REST api 成为https://server:host/MyApi/Notes?search=NoteText== 'My Java Adventure'。API 应提供所有具有 NOTE_TEXT 作为“我的 Java 冒险”的注释。同样,用户也可以在 url 中提供状态,也可以将运算符用作 LIKE。如https://www.baeldung.com/rest-api-search-language-rsql-fiql中所述,我能够通过 rsql 解析器完成此操作
现在我有一个额外的要求,即基于用户安全 person_id 过滤器应该自动应用于查询。
我发现我们没有 findBy 方法可以接受 Specification、Pageable 和额外的 personId。例如我不能有一个存储库函数作为 findByPersonId(Specification spec, Pageable page, Long personId);
本来想用SpEL来用的,后来发现如果在findBy方法上使用@Query注解,就会忽略Specifications。
似乎我无法同时拥有 Specification 和 @Query 。我只需要使用规范添加更多子句。实际上,我的 where 子句非常复杂,我必须附加它并且使用规范来获取它似乎很困难。它类似于 Select * from NOTES where exists (select 'x' from ABC a where n.person_id = a.person_id)
有没有办法我可以编写 @Query 并在其上使用规范?
理想情况下,我已经实现了类似的查询
select * from test.SCH_FORUM_THREAD t
where exists (select 'x' from test.FORUM_THREAD_ACCESS fta, school.SCH_GROUP_PERSON gp
where gp.GROUP_ID = fta.GROUP_ID
and t.THREAD_ID = fta.THREAD_ID
and gp.PERSON_ID = :personId)
or exists (select 'x' from test.FORUM_THREAD_ACCESS fta
where fta.THREAD_ID = t.THREAD_ID
and fta.PERSON_ID = :personId);
所以有两个带有 or 条件的存在子句。通过遵循如何使用 JPA Criteria Builder 编写查询(包括子查询和存在),我能够使第二个存在
现在挣扎第一个存在,因为它也加入了。任何想法如何使用规范来做到这一点。同样存在两个,这是否意味着我需要两个规范。我可以在一个规范中实现它吗?
解决方案
我能够通过创建复杂的规范代码来解决它。就像是
@Override
public Predicate toPredicate(Root<ForumThread> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Subquery<ForumThread> subQuery = query.subquery(ForumThread.class);
Root<ForumThread> subRoot = subQuery.from(ForumThread.class);
Join<ForumThreadAccess, GroupPerson> fragpjoin = subRoot.join("groupPersons");
Predicate threadPredicate = builder.equal(root.get("threadId"), subRoot.get("threadId"));
Predicate personPredicate = builder.equal(fragpjoin.get("personId"), personId);
subQuery.select(subRoot).where(threadPredicate, personPredicate);
Predicate existsGroupPredicate = builder.exists(subQuery);
Subquery<ForumThreadAccess> subQuery1 = query.subquery(ForumThreadAccess.class);
Root<ForumThreadAccess> subRoot1 = subQuery1.from(ForumThreadAccess.class);
Predicate threadPredicate1 = builder.equal(root.get("threadId"), subRoot1.get("threadId"));
Predicate personPredicate1 = builder.equal(subRoot1.get("personId"), personId);
subQuery1.select(subRoot1).where(threadPredicate1, personPredicate1);
Predicate existsPersonPredicate = builder.exists(subQuery1);
return builder.or(existsGroupPredicate,existsPersonPredicate);
}
为了使其工作,您的实体还应该有适当的@OneToMany 和@ManyToMany。
谢谢
推荐阅读
- scala - 使用 NSC 编译 Scala 对象
- javascript - 如何按布尔字符串字段对javascript对象集合进行排序
- makefile - makefile:意外标记“,”附近的语法错误
- c# - How to create a C# application that opens "cmd.exe" in another window?
- python - 所有标记的seaborn散点图标记大小
- javascript - 如何将数据从一个 Marketo 实例提交到另一个?
- singularity-container - 奇点提取、编辑和重建图像
- node.js - ftpPublish 声明性管道
- android - 如何让安卓应用永不关闭?(模拟亭模式)
- javascript - 我的 javascript 模块中的函数未定义