【问题标题】:Spring Data JPA @Query with Specification带有规范的 Spring Data JPA @Query
【发布时间】:2020-05-20 03:58:06
【问题描述】:

我需要创建一个 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注解,就会忽略规范。

似乎我无法同时拥有 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 条件的存在子句。通过关注How to write query(include subquery and exists) using JPA Criteria Builder

,我能够使第二个存在

现在与第一个存在斗争,因为它也加入了。任何想法如何使用规范来做到这一点。 同样存在两个,这是否意味着我需要两个规范。我可以在一个规范中实现它吗?

【问题讨论】:

标签: spring-boot spring-data-jpa


【解决方案1】:

我能够通过创建复杂的规范代码来解决它。像

@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。

谢谢

【讨论】:

    猜你喜欢
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 2021-11-09
    • 2016-02-17
    • 2017-01-12
    • 2019-05-25
    • 1970-01-01
    相关资源
    最近更新 更多