Как добавить коллекции в класс передачи данных в режиме гибернации

#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 действительно важно для вашего проекта.