Отображение сложного конструктора нативного запроса в спящем режиме
Java, Spring Data JPA
У меня есть 2 лица:
class Source {
Integer id;
String name;
}
class Item {
Integer id;
String name;
Integer sourceId;
}
Мне нужен статистический результат запроса:
select s.id source_id, s.name source_name, count(i.id) item_count
from source s
left join item i on s.id = i.source_id
group by s.id
И я хочу получить результат в Java-объект MyResult:
class MyResult {
Source source;
Integer itemCount;
MyResult(Source source, Integer itemCount) {...}
}
Наиболее близким решением является использование @SqlResultSetMapping следующим образом:
@SqlResultSetMapping(
name = "MyResultMapping",
entities = {
@EntityResult(
entityClass = Source.class,
fields = {
@FieldResult(name = "id", column = "source_id"),
@FieldResult(name = "name", column = "source_name"),
}
),
...
???
}
)
ИЛИ ЖЕ
@SqlResultSetMapping(
name = "MyResultMapping",
classes = {
@ConstructorResult(
targetClass = MyResult.class,
columns = {
@ColumnResult(name = "???"),
???
}
)
}
)
Со вторым вариантом я могу использовать что-то вроде этого:
MyResult(Integer sourceId, String sourceName, Integer itemsCount) {
this.source = new Source(sourceId, sourceName);
this.itemsCount = itemsCount;
}
но я хочу, чтобы он автоматизировался с @SqlResultSetMapping... (потому что мои реальные объекты более сложные)
1 ответ
В Spring Data JPA лучше использовать прогнозы для достижения ваших целей, например:
public interface SourceWithItemCount {
Source getSource();
Integer getItemCount();
}
Затем в вашем репозитории Source создайте метод запроса HQL, например:
public interface SourceRepo extends JpaRepository<Source, Integer> {
@Query("select s as source, count(i) like itemCount from Source s left join Item i on i.sourceId = s.id group by s"
List<SourceWithItemCount> getSourcesWithItemCount();
}
Важное замечание - использовать псевдонимы для возвращаемых значений (s as source
и т.д.) это позволяет Spring Data JPA отображать их в свойствах проекций.
Join on <condition>
работает с Hibernate версии 5.1+ (если я не ошибаюсь), поэтому я рекомендую вам создать классическое отношение один-ко-многим между вашими объектами, например, так:
@Entity
class Source {
@Id private Integer id;
private String name;
@OneToMany @JoinColumn(name = "source_id") private List<Item> items;
}
@Entity
class Item {
@Id private Integer id;
private String name;
}
Затем создайте метод запроса JPQL, поддерживаемый всеми версиями Hibernate (и другими поставщиками ORM):
@Query("select s as source, count(i) like itemCount from Source s left join s.items i group by s"
List<SourceWithItemCount> getSourcesWithItemCount();