Hibernate Native SQL Query извлечение сущностей и коллекций

Это моя ситуация, у меня есть два основных POJO, которым я дал простое сопоставление гибернации:

Person
  - PersonId
  - Name
  - Books

Book
  - Code
  - Description

Мой SQL-запрос возвращает строки, которые выглядят следующим образом:

PERSONID NAME       CODE DESCRIPTION
-------- ---------- ---- -----------
1        BEN        1234 BOOK 1
1        BEN        5678 BOOK 2
2        JOHN       9012 BOOK 3

Мой спящий запрос выглядит так:

session.createSQLQuery("select personid, name, code, description from person_books")  
       .addEntity("person", Person.class)
       .addJoin("book", "person.books")
       .list();

Это относится к разделу: 18.1.3 документации по спящему режиму: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/querysql.html#d0e17464

Я ожидаю получить в своем списке 2 объекта Person с содержащимися объектами book в коллекции books :

List
 |- Ben
 |   |- Book 1
 |   '- Book 2
 '- John
     '- Book 3

То, что я на самом деле вижу, это:

List
 |- Object[]
 |   |- Ben
 |   |   |- Book 1
 |   |   '- Book 2
 |   '- Book 1
 |- Object[]
 |   |- Ben
 |   |   |- Book 1
 |   |   '- Book 2
 |   '- Book 2
 '- Object[]
     |- John
     |   '- Book 3
     '- Book 3

Кто-нибудь знает, можно ли получить то, что я хочу, используя этот метод?


person Ben    schedule 25.08.2011    source источник


Ответы (5)


Расширение ответа Мэтьюза. Чтобы заставить hibernate возвращать только список людей, выполните следующие действия:

List<Person> peopleWithBooks = session.createSQLQuery(
   "select {p.*}, {b.*} from person p, book b where <complicated join>").
     .addEntity("p", Person.class)
     .addJoin("b", "p.books")
     .addEntity("p", Person.class)
     .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
     .list();

Связанные объекты Book будут извлекаться и инициализироваться без дополнительного вызова db.

Дубликат

 .addEntity("p", Person.class)

необходимо, потому что

 .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)

работает с последним добавленным объектом.

person ehrhardt    schedule 20.06.2013
comment
Это принесет все для Person и Book. Что делать, если вы хотите выбрать только определенные свойства для повышения производительности. Как я понял ничего кроме * или п.* не работает. - person T3rm1; 12.02.2014
comment
Использование {p.*}, {b.*} также устраняет дополнительную проблему подвыборки для books. - person v.ladynev; 27.05.2016
comment
Получает ли это только одну книгу на человека, независимо от количества книг, связанных с человеком? У меня похожая проблема, и я использовал это решение. Он возвращает набор для «присоединенного» объекта, однако не возвращает все значения в нем. Размер набора 1. - person dhamu; 29.10.2019
comment
Мне помог обходной путь с дубликатом .addEntity. Я нашел этот вопрос после того, как задал аналогичный вопрос с другими предложениями - stackoverflow.com/q/62554257/653539 - person Tomáš Záluský; 24.06.2020

Для меня работает следующее:

session.createSQLQuery("select p.*, b.* from person p, book b where <complicated join>").
.addEntity("person", Person.class).addJoin("book", "person.books").list();

Это возвращает Object[], содержащий список Person, каждый из которых содержит список Book. Он делает это в одном SQL-запросе. Я думаю, ваша проблема в том, что вы специально ничего не называете человеком.

РЕДАКТИРОВАТЬ: метод возвращает Object[], но массив заполняется экземплярами Person и только экземплярами Person.

Если Hibernate не понимает, как сопоставить ваши классы или не может понять, как сопоставить соединение, он вернет список объектов. Убедитесь, что у вас есть только одна комбинация Person/Book в каждой строке.

person Matthew Farwell    schedule 25.08.2011
comment
То, что я ожидал, было списком Person, а не списком Object[] с дубликатами людей, когда у них есть более одной книги. См. мой ответ для ссылки на отчет об ошибке hibernate jira. - person Ben; 26.08.2011
comment
Извините, чтобы было понятно, метод возвращает Object[], но массив заполнен Person и только Person. У меня там нет книг. - person Matthew Farwell; 26.08.2011

HHH-2831 Собственные SQL-запросы с addJoin или возвратом массивов объектов вместо отдельных объектов

Такое поведение вызвано известной ошибкой. Дох, надо было усерднее искать!

person Ben    schedule 26.08.2011
comment
Обновление: исправьте ссылку. Ответ @ehrhardt устраняет эту проблему для Hibernate 5.1: stackoverflow.com/a/17210746/3405171 - person v.ladynev; 27.05.2016

Должен ли ваш запрос быть в таблице person вместо person_books?

session.createSQLQuery("select * from person")  
   .addEntity("person", Person.class)
   .addJoin("book", "person.books")
   .list();
person legendofawesomeness    schedule 25.08.2011
comment
Я упростил этот пример для краткости. В моем фактическом использовании person_books — это сложный запрос, у hibernate нет возможности получить информацию о книге без моего предоставления ее в запросе. Я извлекаю большое количество строк для человека и предпочел бы не выполнять дополнительный запрос, чтобы найти книги для каждого человека. Если я не смогу найти решение, я, вероятно, воспользуюсь этим методом, но просто пропущу строки, в которых Person не меняется. - person Ben; 25.08.2011

Насколько мне известно, невозможно вернуть «объединенный» объект из SQL-запроса. Вы получите только массив объектов. Что я сделал в этой ситуации, так это то, что я создал новый конструктор для моего объединенного объекта, который принимал массив объектов в качестве аргумента. Затем я построил это вручную.

person Basanth Roy    schedule 26.08.2011