#java #spring #hibernate #jpa #jpql
#java #spring #переход в спящий режим #jpa #jpql
Вопрос:
Я пытаюсь заставить проекции работать @query
в JPA с объединенными столбцами также в качестве другого проекта.
Допустим, у меня есть 2 объекта: курс и студент, а у студента может быть много курсов, и внешний ключ находится в таблице курсов:
student(id, name, email, age, grade, uuid)
course(id, name, uuid, student_id)
И у меня есть проекции, подобные этим:
public interface CourseProjection {
UUID getUuid();
}
И,
public interface StudentProjection {
String getName();
String getEmail();
Set<CourseProjection> getCourses();
}
В сущности:
public class Student {
// other code
@OneToMany(mappedBy = "student")
private Set<Course> courses = new LinkedHashSet<>();
}
Мне нужно выполнить LIKE
поиск по нескольким столбцам, включая uuid курса.
Мне также нужно, я также хочу разбивку на страницы.
Итак, в репозитории я хочу сделать что-то вроде:
@Repository
interface StudentRepository extends JpaRepository<Student, UUID> {
@Query(
value = "SELECT * FROM student s LEFT JOIN courses c ON s.id =
c.student_id WHERE s.name LIKE %str% OR c.student_id::text LIKE %str%",
nativeQuery = true
)
Page<StudentProjection> findAllByKeyword(String keyword, Pageable pageable);
}
Я хочу, чтобы результат выглядел следующим образом:
[
{
name: John
email: johndoe@gmail.com
courses: [
"course_uuid_1",
"course_uuid_2"
]
}
{
...
}
]
Есть предложения о том, как этого добиться?
Комментарии:
1. Вложенные проекции должны работать. Какой результат вы получаете?
2. И почему вы используете собственный запрос?
3. @AlanHay 1. В результате у меня получается, что courses равен null. 2. Поскольку это собственный запрос.
SELECT *
без этого не работало бы.4. Кстати, это будет работать нормально, если я не использую
StudentProjection
, а просто используюStudent
.
Ответ №1:
У вас есть попытка:
-
интерфейс StudentRepository расширяет JpaRepository, excerptProjection = projectionName.class Перенести эту проекцию в репозиторий.
-
Https:domain/contextpath/students/search/findAllByKeyword?projection=projectionName Чтобы применить проекцию для этого rest api. И вам нужно добавить дополнительную конфигурацию, как показано ниже:
@Configuration public class RepositoryConfig extends RepositoryRestConfigurerAdapter { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.getProjectionConfiguration().addProjection(projectionName.class)); } }
Комментарии:
1. 1. Я не получил
excerptProjection = projectionName.class
часть. Не могли бы вы предоставить немного больше деталей? 2. Это не вариант, URL API не должен знать об этой проекции. Я бы предпочел не использовать проекцию, если это так.
Ответ №2:
При использовании вложенных закрытых проекций Spring Data с пользовательскими запросами вам необходимо убедиться, что вы определенно:
- Вложенные проекции
- Явное объявление псевдонимов столбцов
Я столкнулся с той же проблемой, пытаясь выяснить, как ее решить. Ваш код работал бы совершенно нормально, если бы вы просто выполнили:
public interface StudentProjection {
String getName();
String getEmail();
Set<CourseProjection> getCourses();
interface CourseProjection {
UUID getUuid();
}
}
А затем использовал ваш пользовательский запрос следующим образом:
@Query(nativeQuery = true,
value = "SELECT s.name as name, s.email as email, c.uuid as uuid "
"FROM student s "
"LEFT JOIN courses c ON s.id = c.student_id "
"WHERE s.name LIKE %str% OR c.student_id::text LIKE %str%")
Page<StudentProjection> findAllByKeyword(String keyword, Pageable pageable);
Я также считаю, что не было необходимости использовать собственный запрос, вы могли бы просто использовать HQL/JPQL
вместо этого или даже Spring Data query methods
.
Я знаю, что этот вопрос немного устарел, но он может быть полезен другим людям.