Как заставить JPA @ query работать с проекцией, в которой есть другая проекция

#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:

У вас есть попытка:

  1. интерфейс StudentRepository расширяет JpaRepository, excerptProjection = projectionName.class Перенести эту проекцию в репозиторий.

  2. 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 с пользовательскими запросами вам необходимо убедиться, что вы определенно:

  1. Вложенные проекции
  2. Явное объявление псевдонимов столбцов

Я столкнулся с той же проблемой, пытаясь выяснить, как ее решить. Ваш код работал бы совершенно нормально, если бы вы просто выполнили:

 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 .

Я знаю, что этот вопрос немного устарел, но он может быть полезен другим людям.