Spring Data JPA @Query со спецификацией - PullRequest
0 голосов
/ 04 февраля 2020

У меня есть требование для создания REST API. Api позволяет пользователю предоставлять динамические c критерии поиска в URL. Например, допустим, у меня есть таблица NOTES со столбцами в виде Note_ID, NOTE_TEXT, STATUS, PERSON_ID. Эта таблица используется для ведения записей каждого человека.

Теперь я хочу, чтобы мой REST API был как https://server: host / MyApi / Notes? Search = NoteText == 'My Java adventure'. API должен предоставлять все заметки, имеющие NOTE_TEXT как «Мое Java приключение». Точно так же пользователь может предоставить статус также в URL, а также он может использовать операторы как LIKE. Я смог сделать это с помощью синтаксического анализатора r sql, как указано в https://www.baeldung.com/rest-api-search-language-rsql-fiql

Теперь у меня есть дополнительное требование, чтобы на основе запроса автоматически применялся фильтр person_id безопасности пользователя.

Я обнаружил, что у нас не может быть метода findBy, который может принимать Specification, Pageable и дополнительный personId. Например, у меня не может быть функции репозитория как findByPersonId (спецификация spe c, Pageable page, Long personId);

Я думал об использовании SpEL для его использования, но потом я обнаружил, что если мы используем @ Аннотация запроса к методу findBy. Спецификации игнорируются.

Похоже, я никак не могу получить спецификацию и @Query одновременно. Мне нужно добавить больше предложений, используя только спецификации. В действительности мое предложение where очень сложное, и я должен добавить его, и получить его со спецификацией кажется трудным. Это что-то вроде Select * из NOTES, где существует (выберите 'x' из AB C a, где 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);

Итак, существует два предложения с условием или условием. Мне удалось создать второе существующее, следуя Как написать запрос (включая подзапрос и существует), используя JPA Criteria Builder

Теперь борется с первым, поскольку оно также имеет соединение. Любая идея, как это сделать с помощью спецификации. Кроме того, поскольку существует два, означает ли это, что мне нужны две спецификации. Могу ли я достичь этого в одной спецификации.

1 Ответ

0 голосов
/ 05 февраля 2020

Мне удалось решить эту проблему путем создания сложного кода спецификации. Что-то вроде

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

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...