Вопрос довольно широкий и затрагивает несколько аспектов:
- пользовательский метод репозитория JPA с использованием
@Query
- выбора результатов при отображении
@Query
@Query
приводит к интерфейсу - , предоставляя новый метод хранилища с помощью
@RepositoryRestResource
TLDR: написал пример того, о чем говорится с парой базовых c тестов https://github.com/ivarprudnikov/test-spring-jpa-repository-query-exposed-through-http
пользовательский метод репозитория JPA с использованием @Query
Как вы уже упоминали, это довольно просто, просто аннотируйте метод с помощью @Query
и убедитесь, что вы возвращаете тип соответствует тому, что возвращается из запроса, например:
public interface FooRepository extends JpaRepository<FooEntity, Long> {
@Query(nativeQuery = true, value = "select f from foo f where f.name = :myParam")
Optional<FooEntity> getInSomeAnotherWay(String myParam);
}
выбор результатов в вашем @Query
Вы уже привели пример, но я упрощу, чтобы сделать его проще и короче.
Данные сущности FooEntity.java
и BarEntity.java
:
@Entity
@Table(name = "foo")
public class FooEntity {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
private String name;
@OneToMany(mappedBy = "foo")
private Set<BarEntity> bars = new HashSet<>();
// getter setters excluded for brevity
}
@Entity
@Table(name = "bar")
public class BarEntity {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
private String name;
@ManyToOne(targetEntity = FooEntity.class)
@JoinColumn(name = "foo_id", nullable = false, foreignKey = @ForeignKey(name = "fk_bar_foo"))
private FooEntity foo;
// getter setters excluded for brevity
}
Теперь мы хотим вернуть пользовательский набор результатов, который содержит FooEntity.name
и количество FooEntity.bars
:
SELECT f.name as name, count(b.id) as barCount FROM foo f, bar b WHERE f.id = :id AND b.foo_id = :id
+-----------------+----------+
| name | barCount |
+-----------------+----------+
| Jonny tables | 1 |
+-----------------+----------+
отображение @Query
результатов на интерфейс
T o для отображения вышеупомянутого набора результатов нам нужен интерфейс, в котором получатели хорошо отражают то, что выбирается:
public interface ProjectedFooResult {
String getName();
Long getBarCount();
}
Теперь мы можем переписать наш метод репозитория так:
@Query(nativeQuery = true,
value = "SELECT f.name as name, count(b.id) as barCount FROM foo f, bar b WHERE f.id = :id AND b.foo_id = :id")
Optional<ProjectedFooResult> getByIdToProjected(Long id);
, открывая новый метод репозитория через @RepositoryRestResource
Я не очень знаком с этим, но после добавления зависимости org.springframework.data:spring-data-rest-hal-browser
я получил этот приятный интерфейс, который отображал доступные методы после того, как репозиторий был помечен @RepositoryRestResource
. Для данного репозитория, который содержит вышеупомянутые детали:
@RepositoryRestResource(path = "foo")
public interface FooRepository extends JpaRepository<FooEntity, Long> {
@Query(nativeQuery = true, value = "SELECT f.name as name, count(b.id) as barCount FROM foo f, bar b WHERE f.id = :id AND b.foo_id = :id")
Optional<ProjectedFooResult> getByIdToProjected(Long id);
}
, метод будет доступен через http://localhost:8080/foo/search/getByIdToProjected?id=1
при локальном запуске.
Как упоминалось выше, эталонная реализация находится на Github https://github.com/ivarprudnikov/test-spring-jpa-repository-query-exposed-through-http
Дополнительная полезная документация для «Пользовательских реализаций для репозиториев данных Spring»