JPA : How to convert a native query result set to POJO class collection
JPA : Как преобразовать собственный набор результатов запроса в коллекцию классов POJO
Я использую JPA в своем проекте.
Я пришел к запросу, в котором мне нужно выполнить операцию объединения для пяти таблиц. Итак, я создал собственный запрос, который возвращает пять полей.
Теперь я хочу преобразовать результирующий объект в класс java POJO, который содержит те же пять строк.
Есть ли в JPA какой-либо способ напрямую преобразовать этот результат в список объектов POJO??
Я пришел к следующему решению..
@NamedNativeQueries({ @NamedNativeQuery( name = "nativeSQL", query = "SELECT * FROM Actors", resultClass = db.Actor.class), @NamedNativeQuery( name = "nativeSQL2", query = "SELECT COUNT(*) FROM Actors", resultClass = XXXXX) // <--------------- problem })
Теперь здесь, в resultClass, нужно ли нам предоставлять класс, который является фактической сущностью JPA ? или Мы можем преобразовать его в любой класс JAVA POJO, который содержит те же имена столбцов?
Переведено автоматически
Ответ 1
Я нашел пару решений для этого.
Использование сопоставленных объектов (JPA 2.0)
С помощью JPA 2.0 невозможно сопоставить собственный запрос с POJO, это можно сделать только с сущностью.
Но в этом случае, Jedi, должен быть отображенный класс сущностей.
Альтернативой, позволяющей избежать непроверенного предупреждения здесь, было бы использовать именованный собственный запрос. Итак, если мы объявим собственный запрос в сущности
Это безопаснее, но мы по-прежнему ограничены в использовании отображенной сущности.
Ручное сопоставление
Решение, с которым я немного поэкспериментировал (до появления JPA 2.1), заключалось в сопоставлении с конструктором POJO с использованием небольшого отражения.
Этот метод в основном принимает массив кортежей (возвращаемый собственными запросами) и сопоставляет его с предоставленным классом POJO, ища конструктор с таким же количеством полей и того же типа.
Затем мы можем использовать удобные методы, такие как:
Конечно, в этом случае Jedi не обязательно должна быть отображенная сущность. Это может быть обычный POJO.
Использование сопоставления XML
Я один из тех, кто считает, что добавление всего этого @SqlResultSetMapping довольно инвазивно для моих сущностей, и мне особенно не нравится определение именованных запросов внутри сущностей, поэтому в качестве альтернативы я делаю все это в META-INF/orm.xml файле:
<named-native-query name="GetAllJedi" result-set-mapping="JediMapping"> <query>SELECT name,age FROM jedi_table</query> </named-native-query>
И это все решения, которые я знаю. Последние два - идеальный способ, если мы можем использовать JPA 2.1.
Ответ 2
JPA предоставляет функцию, SqlResultSetMapping которая позволяет вам преобразовывать все, что возвращается из вашего собственного запроса, в сущность или пользовательский класс.
РЕДАКТИРОВАТЬ JPA 1.0 не допускает сопоставления с классами, не являющимися сущностями. Только в JPA 2.1 был добавлен ConstructorResult для сопоставления возвращаемых значений с классом java.
Кроме того, для решения проблемы OP с получением count должно быть достаточно определить сопоставление результирующего набора с помощью одного ColumnResult
Ответ 3
Да, с JPA 2.1 это просто. У вас есть очень полезные аннотации. Они упрощают вашу жизнь.
Сначала объявите свой собственный запрос, затем сопоставление вашего результирующего набора (которое определяет сопоставление данных, возвращаемых базой данных, вашему POJO). Напишите свой класс POJO, на который вы будете ссылаться (для краткости не включен здесь). Последнее, но не менее важное: создайте метод в DAO (например) для вызова запроса. У меня это сработало в приложении dropwizard (1.0.0).
Сначала объявите собственный запрос в классе сущностей (@Entity):
@Entity @NamedNativeQuery ( name = "domain.io.MyClass.myQuery", query = "Select a.colA, a.colB from Table a", resultSetMapping = "mappinMyNativeQuery") // must be the same name as in the SqlResultSetMapping declaration
Ниже вы можете добавить объявление сопоставления результирующего набора:
@SqlResultSetMapping( name = "mapppinNativeQuery", // same as resultSetMapping above in NativeQuery classes = { @ConstructorResult( targetClass = domain.io.MyMapping.class, columns = { @ColumnResult( name = "colA", type = Long.class), @ColumnResult( name = "colB", type = String.class) } ) } )
Позже в DAO вы можете ссылаться на запрос как
public List<domain.io.MyMapping> findAll() { return (namedQuery("domain.io.MyClass.myQuery").list()); }
Вот и все.
Ответ 4
Если вы используете Spring-jpa, это дополнение к ответам и этому вопросу. Пожалуйста, исправьте это, если есть недостатки. В основном я использовал три метода для достижения "результата сопоставления Object[] с pojo" в зависимости от того, какие практические потребности я удовлетворяю:
Достаточно встроенного метода JPA.
Встроенного метода JPA недостаточно, но настроенного sql с его Entity использованием достаточно.
Предыдущие 2 завершились неудачей, и я должен использовать nativeQuery. Вот примеры. Ожидаемый результат pojo:
@Query("select new AntistealingDTO(secretKey, successRate) from Antistealing where ....") Antistealing whatevernamehere(conditions);
Примечание: последовательность параметров конструктора POJO должна быть идентичной как в определении POJO, так и в sql.
Метод 3: Используйте @SqlResultSetMapping и @NamedNativeQuery в Entity качестве примера в ответе Эдвина Далорцо.
Первые два метода вызвали бы множество промежуточных обработчиков, таких как настраиваемые преобразователи. Например, AntiStealing определяет secretKey, перед сохранением вставляется преобразователь для его шифрования. Это привело бы к тому, что первые 2 метода вернули бы преобразованное обратно secretKey что не то, чего я хочу. В то время как метод 3 преодолевает преобразование и возвращается secretKey таким же, каким оно сохранено (зашифрованным).