1. Знайомство
Ще одна корисна річ, про яку хотілося б розповісти — це NativeQuery. Як ти знаєш, за допомогою NativeQuery можна писати запити на рідному SQL. Однак ще цікавішим є те, що ти можеш не використовувати мапінг класів під час отримання результату запиту.
Я краще покажу тобі приклад:
List<Object[]> люди = session.createNativeQuery("SELECT * FROM Person" ).list();
У цьому прикладі ми не передаємо клас, який відповідає рядкам результату запиту — натомість використовується просто масив об'єктів Object.
Це може бути корисним, якщо ти хочеш зробити вибірку лише пари колонок таблиці. Приклад:
List<Object[]> люди = session.createNativeQuery("SELECT id, name FROM Person").list();
for(Object[] person : persons) {
Number id = (Number) person[0];
String name = (String) person[1];
}
Це чимось схоже на підхід JDBC, коли ти отримуєш об'єкт ResultSet і читаєш дані з його рядків.
Однак Hibernate пропонує різні способи зробити цю справу надійнішою. Наприклад, ти можеш вказати тип колонок, які хочеш віднімати. Приклад:
Query<Object[]> query = session.createNativeQuery("SELECT id, name FROM Person");
query.addScalar("id", StandardBasicTypes.LONG< /span>);
query.addScalar("name", StandardBasicTypes.STRING< /span>);
List<Object[]> люди = query.list();
for(Object[] person : persons) {
Long id = (Long) person[0];
String name = (String) person[1];
}
2. Entity мапінг
Також ти можеш явно вказати клас, який Hibernate має використовувати під час парсингу результату NativeQuery. Зробити це можна у різний спосіб.
Query<Person> query = session.createNativeQuery("SELECT * FROM Person" )
.addEntity(Person.class);
.list();
І звісно, старий-добрий відомий тобі формат:
Query<Person> query = session.createNativeQuery("SELECT * FROM Person" , Person.class).list();
Перший підхід — це рідний підхід Hibernate, а другий — це JPA. Підхід JPA зручніший і лаконічніший, оскільки цей стандарт придумали вже після того, як Hibernate проіснував багато років. Hibernate розвивався і був змушений підтримувати старі підходи для збереження сумісності зі своїми старими версіями.
До речі, завдяки своєму підходу Hibernate дозволяє підключати не один клас до мапінг результату запиту, а кілька. Приклад:
List<Phone> results = session.createNativeQuery(
"SELECT {ph.*}, {pr.*}" +
"FROM Phone ph" +
"JOIN Person pr ON ph.person_id = pr.id")
.addEntity("ph", Phone.class)
.addJoin("pr", "ph.person")
.list();
for (Phone. phone : results) {
assertNotNull( phone.getPerson().getName() );
}
Такий підхід за допомогою NativeQuery можна використовувати для прискорення вибірки даних із бази. Якщо ти знаєш, що якісь стовпчики тобі не потрібні, ти можеш їх не вказувати у запиті.
Також ти можеш одразу завантажити всі дочірні сутності, навіть якщо Hibernate хоче використовувати Cache або механізм LazyLoading. До того ж, у твоїх дочірніх сутностей може бути багато колонок у базі, і ти можеш відібрати лише деякі з них.
3. DTO-мапінг
Також Hibernate дозволяє використовувати для мапінгу результату не Entity-класів. Класи, які не мають жодних анотацій, і які не замаплені на будь-які таблиці.
Приклад:
public class PersonSummaryDTO {
private Number id;
private String name;
public Number getId() {
return id;
}
public void setId(Number id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
List<PersonSummaryDTO> dtos = session.createNativeQuery(
"SELECT p.id as \"id\", p.name as \"name\" FROM Person p")
.setResultTransformer(Transformers.aliasToBean(< span class="text-brown">PersonSummaryDTO.class) )
.list();
Оскільки анотацій у класу PersonSummaryDTO немає, імена колонок у SQL-запиті повинні точно збігатися з іменами полів класу PersonSummaryDTO.
Таке буває дуже корисно, якщо ти читаєш дані із зовнішньої бази даних, до якої твоя програма підключена тільки в режимі read-only. Тобто тобі дали доступ до таблиць, у яких по 50+ колонок, вони зберігають дані в денормалізованому вигляді для прискорення вибірки.
Або припустимо, що хтось вирішив зберігати ієрархію класів в одній таблиці, а за п'ять років ця таблиця так розрослася, що чорт ногу зломить. Тобі потрібно вибрати з цієї таблиці пару колонок (Id та ім'я користувача) та віддати їх клієнту.
Думаю, все зрозуміло, але якщо хочеш поринути у цю тему глибше, то докладніше можна почитати за посиланням:
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ