Я использую 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, который содержит те же имена столбцов?
Ответы:
JPA предоставляет
SqlResultSetMapping
который позволяет отображать любые результаты из вашего собственного запроса в сущностьили пользовательский класс,РЕДАКТИРОВАТЬ JPA 1.0 не разрешает сопоставление с не-сущностными классами. Только в JPA 2.1 ConstructorResult был добавлен к возвращаемым значениям карты java-класса.
Кроме того, для проблемы OP с получением количества должно быть достаточно, чтобы определить отображение набора результатов с одним
ColumnResult
источник
ConstructorResult
как один из параметров,SqlResultSetMapping
который позволяет использовать pojo со всеми полями, установленными в конструкторе. Я обновлю ответ.Я нашел пару решений для этого.
Использование сопоставленных объектов (JPA 2.0)
При использовании JPA 2.0 невозможно сопоставить собственный запрос с POJO, это можно сделать только с помощью объекта.
Например:
Но в этом случае
Jedi
должен быть сопоставленный класс сущности.Альтернативой, чтобы избежать неконтролируемого здесь предупреждения, было бы использование именованного собственного запроса. Так что, если мы объявим собственный запрос в сущности
Тогда мы можем просто сделать:
Это безопаснее, но мы по-прежнему ограничены в использовании сопоставленной сущности.
Ручное картографирование
Решение, которое я немного экспериментировал (до появления JPA 2.1), заключалось в отображении конструктора POJO с использованием небольшого отражения.
Этот метод в основном берет массив кортежей (как возвращено нативными запросами) и сопоставляет его с предоставленным классом POJO, ища конструктор, который имеет такое же количество полей и того же типа.
Тогда мы можем использовать удобные методы, такие как:
И мы можем просто использовать эту технику следующим образом:
JPA 2.1 с @SqlResultSetMapping
С появлением JPA 2.1 мы можем использовать аннотацию @SqlResultSetMapping для решения проблемы.
Нам нужно объявить отображение набора результатов где-то в сущности:
И тогда мы просто делаем:
Конечно, в этом случае
Jedi
не требуется отображать объект. Это может быть обычный POJO.Использование XML Mapping
Я один из тех, кто находит добавление всех этих
@SqlResultSetMapping
довольно инвазивных в мои сущности, и мне особенно не нравится определение именованных запросов внутри сущностей, поэтому я также делаю все это вMETA-INF/orm.xml
файле:И это все решения, которые я знаю. Последние два являются идеальным способом, если мы можем использовать JPA 2.1.
источник
@SqlResultSetMapping
Должен быть помещен в сущность, потому что именно из этого JPA будет читать метаданные. Вы не можете ожидать, что JPA будет проверять ваши POJO. Объект, в который вы помещаете отображение, не имеет значения, возможно, тот, который больше связан с вашими результатами POJO. В качестве альтернативы отображение может быть выражено в XML, чтобы избежать связи с совершенно не связанной сущностью.@SqlResultSetMapping
ним, то, возможно, стоит отметить, чтоJedi
классу потребуется конструктор, содержащий все аргументы, и@ColumnResult
аннотации может потребоватьсяtype
добавить атрибут к преобразованиям, который может быть неявным (мне нужно было добавитьtype = ZonedDateTime.class
некоторые столбцы).Да, с JPA 2.1 это легко. У вас есть очень полезные аннотации. Они упрощают вашу жизнь.
Сначала объявите свой собственный запрос, а затем сопоставление набора результатов (которое определяет отображение данных, возвращаемых базой данных в ваши POJO). Напишите ваш класс POJO для ссылки (не включен здесь для краткости). И последнее, но не менее важное: создайте метод в DAO (например) для вызова запроса. Это работало для меня в приложении dropwizard (1.0.0).
Сначала объявите собственный запрос в классе сущности:
Ниже вы можете добавить объявление отображения набора результатов:
Позже в DAO вы можете ссылаться на запрос как
Вот и все.
источник
Если вы используете
Spring-jpa
, это дополнение к ответам и этот вопрос. Пожалуйста, исправьте это, если есть какие-либо недостатки. В основном я использовал три метода для достижения «результата сопоставленияObject[]
с pojo», основываясь на том, что я на практике понимаю:sql
егоEntity
.Первые 2 не удалось, и я должен использовать
nativeQuery
. Вот примеры. Пойо ожидал:Метод 1 : Измените pojo в интерфейс:
И хранилище:
Метод 2 : Репозиторий:
Примечание: последовательность параметров конструктора POJO должна быть одинаковой как в определении POJO, так и в sql.
Способ 3 : используйте
@SqlResultSetMapping
и@NamedNativeQuery
вEntity
качестве примера в ответе Эдвина Далорсо.Первые два метода вызвали бы многие промежуточные обработчики, такие как настраиваемые преобразователи. Например,
AntiStealing
определяетsecretKey
, прежде чем он будет сохранен, вставляется конвертер для его шифрования. Это приведет к тому, что первые 2 метода вернут конвертированный обратно,secretKey
что не то, что я хочу. Хотя способ 3 будет преодолевать конвертер, и возвращаемыйsecretKey
будет таким же, как он хранится (зашифрованный).источник
Процедура развертывания может быть выполнена для назначения результатов не-сущности (то есть Beans / POJO). Процедура заключается в следующем.
Использование для реализации JPA-Hibernate.
источник
JobDTO
должен иметь конструктор по умолчанию. Или вы можете реализовать свой собственный преобразователь на основеAliasToBeanResultTransformer
реализации.Сначала объявите следующие аннотации:
Затем аннотируйте ваш POJO следующим образом:
Затем напишите аннотацию процессора:
Используйте вышеуказанные рамки следующим образом:
источник
BeanUtils
?Самый простой способ - использовать проекции . Он может отображать результаты запросов непосредственно в интерфейсы и его легче реализовать, чем с помощью SqlResultSetMapping.
Пример показан ниже:
Поля из проектируемого интерфейса должны соответствовать полям в этом объекте. В противном случае отображение поля может нарушиться.
Также, если вы используете
SELECT table.column
нотацию, всегда определяйте псевдонимы, совпадающие с именами из объекта, как показано в примере.источник
В спящем режиме вы можете использовать этот код, чтобы легко сопоставить ваш собственный запрос.
источник
Использование Hibernate:
источник
Старый стиль с использованием ResultSet
источник
Поскольку другие уже упомянули все возможные решения, я делюсь своим решением.
В моей ситуации с
Postgres 9.4
, во время работы сJackson
,Я уверен, что вы можете найти то же самое для других баз данных.
Также FYI, JPA 2.0 собственные результаты запроса в виде карты
источник
Не уверен, подходит ли это здесь, но у меня был похожий вопрос и я нашел следующее простое решение / пример для меня:
В моем случае мне пришлось использовать части SQL, определенные в строках где-то еще, поэтому я не мог просто использовать NamedNativeQuery.
источник
Старый стиль с использованием Resultset
источник
Мы решили проблему следующим образом:
источник
Ниже приведен пример использования POJO в качестве псевдо-сущности для получения результата из собственного запроса без использования сложного SqlResultSetMapping. Просто нужно две аннотации, пустой @Enity и фиктивный @Id в вашем POJO. @Id может использоваться в любом поле по вашему выбору, поле @Id может иметь дублирующиеся ключи, но не нулевые значения.
Поскольку @Enity не отображается ни на одну физическую таблицу, этот POJO называется псевдо-сущностью.
Среда: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Вы можете скачать полный проект Maven здесь
Собственный запрос основан на примере сотрудников MySQL. Ddev http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
источник
list
якобы списокEmployee
, почему ваш цикл for-each выполняет итерации по типуObject
? Если вы напишете цикл for-each как,for(Employee emp : list)
то обнаружите, что ваш ответ неправильный, и содержимое вашего списка не является сотрудниками, и что это предупреждение, которое вы подавили, имело целью предупредить вас об этой потенциальной ошибке.List<Employee> list = (List<Employee>) query.getResultList();
об улучшении Changefor (Object emp : list)
tofor (Employee emp : list)
, но без ошибок, если его оставить,Object emp
поскольку list является экземпляромList<Employee>
. Я изменил код в git проекте, но не здесь, чтобы ваш комментарий был актуален для оригинального сообщенияQuery query = em.createNativeQuery("select * ...", Employee.class);
и persistence.xml, нативный запрос возвращает список Employee. Я только что проверил и запустил проект без проблемы. Если вы настроите пример базы данных mysql для сотрудников локально, вы также сможете запустить проектEmployee
я полагаю, сущность. Не так ли?если вы используете Spring, вы можете использовать
org.springframework.jdbc.core.RowMapper
Вот пример:
источник
Использование Hibernate:
источник
Простой способ преобразования SQL-запроса в коллекцию классов POJO,
источник
Все, что вам нужно, это DTO с конструктором:
и назовите это:
источник
Использование
DTO Design Pattern
. Он был использован вEJB 2.0
. Сущность была управляемой контейнером.DTO Design Pattern
используется для решения этой проблемы. Но, это может быть использовано сейчас, когда приложение разрабатываетсяServer Side
иClient Side
отдельно.DTO
используется, когдаServer side
не хочет проходить / возвращатьсяEntity
с аннотацией кClient Side
.Пример DTO:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- это может быть необходимо
источник