#java #hibernate #orm
#java #спящий режим #orm
Вопрос:
У меня есть следующая настройка, в которой класс содержит коллекцию. При запросе экземпляров этого класса мне нравится заполнять класс передачи данных, а не класс данных. Однако Hibernate генерирует неправильный SQL-запрос. Чего мне не хватает?
Отображение в режиме гибернации:
<class name="Thread" table="tbl_threads" schema="dbo">
<id name="Id" type="integer">
<column name="i_id"/>
<generator class="identity"/>
</id>
<set name="keywords" inverse="true" lazy="false" cascade="all-delete-orphan" optimistic-lock="false">
<key>
<column name="thread_id" not-null="true"/>
</key>
<one-to-many class="Comment"/>
</set>
<!-- ... -->
</class>
и
<class name="ThreadKeyword" table="tbl_keywords" schema="dbo">
<composite-id name="id"
class="se.ericsson.eab.sdk.fido.server.api.pojos.report.ReportThreadKeywordId">
<key-property name="keywordId" type="integer">
<column name="keyword_id" />
</key-property>
<key-property name="threadId" type="integer">
<column name="thread_id" />
</key-property>
</composite-id>
<!-- ... -->
</class>
Используемый мной HQL
SELECT new Composite(t.id, t.keywords, ...)
FROM Thread t, ThreadKeyword tk
WHERE t.id = tk.id.threadId
Это генерирует SQL, в котором часть ВЫБОРА содержит только точку для атрибута ключевого слова:
select thread1_.report_id as col_0_0_, . as col_92_0_
from dbo.tbl_thread reportthre0_ inner join
dbo.tbl_keywords keywords4_ on reportthre0_.i_id=keywords4_.thread_id
Он отлично работает, когда я запрашиваю класс данных напрямую, т.Е.
SELECT t
FROM Thread t, ThreadKeyword tk
WHERE t.id = tk.id.threadId
Насколько я понимаю, Hibernate не найдет имя столбца для ключевых слов в таблице потоков. Это правильно, поскольку это коллекция. Его скорее нужно заполнить с помощью последующих запросов. Если я опущу ключевые слова в конструкторе для составного класса, запрос будет выполнен правильно, но Hibernate не заполнит набор.
Как мне заполнить набор ключевых слов?
Комментарии:
1. Составной класс не имеет отображения в режиме гибернации, поскольку раньше он работал с простыми свойствами без сопоставления.
Ответ №1:
Вы не можете сделать это с коллекцией.
t.id является столбцом / значением
таким образом, Hibernate преобразует это в thread1_.report_id как col_0_0_. Hibernate даже присвоил ему псевдоним col_0_0_
t.keywords — это набор значений, поэтому Hibernate просто не может преобразовать коллекцию в столбец / значение.
Запрос включает список столбцов, которые будут включены в конечный результат сразу после ключевого слова SELECT — Википедия
Теперь
SELECT t FROM Thread t, ThreadKeyword tk WHERE t.id = tk.id.threadId
работает нормально, потому что Hibernate знает, как перевести запрос, который у вас есть, в SQL.
Комментарии:
1. Привет, хорошо, я угадал правильно. Но, учитывая ограничения, которые мне нужны для использования
Composite
класса, есть ли способ получить ключевые слова в этот класс?2. Дело в том, что ThreadKeyword по-прежнему является классом сущностей, что противоречит вашему утверждению об объектах передачи данных. Если вы хотите сопоставить объекты с DTO, вы можете использовать Dozer, который является средством сопоставления объектов с объектами. Вы должны использовать HQL, который работает, а затем Dozer для сопоставления результирующего объекта с вашим DTO.
3. Я бы избегал DTO, даже если у них есть некоторые преимущества. Для начала это замедляет разработку, и если вы собираетесь использовать mapper, это также замедляет работу вашего приложения.
4. Не могу позволить себе замедлять работу. Поскольку ключевые слова в основном являются строками, они будут храниться в виде объединенной строки в той же таблице, что и отчет. Это создает избыточность, но не влияет на производительность, по крайней мере, при чтении.
5. Если это единичный случай, вы можете сопоставить объекты Entity с вашими объектами DTO с помощью кода. Это может показаться грязным, но это было бы самым быстрым решением, если использование DTO действительно важно для вашего проекта.