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) // 
 him18 окт. 2018 г., 02:21
он'с использованием jpa, а не весной
 Md. Sajedul Karim16 мая 2018 г., 10:36
Проверьте этот ответ. Он имеет полный ответ:stackoverflow.com/a/50365522/3073945

Ответы на вопрос(17)

Использование сопоставленных объектов (JPA 2.0)

Используя JPA 2.0, невозможно сопоставить собственный запрос с POJO, это можно сделать только с помощью объекта.

Например:

Query query = em.createNativeQuery("SELECT name,age FROM jedi_table", Jedi.class);
@SuppressWarnings("unchecked")
List<jedi> items = (List<jedi>) query.getResultList();
</jedi></jedi>

Но в этом случаеJedi, должен быть сопоставленным классом сущности.

Альтернативой, чтобы избежать неконтролируемого здесь предупреждения, было бы использование именованного собственного запроса. Так что, если мы объявим собственный запрос в сущности

@NamedNativeQuery(
 name="jedisQry", 
 query = "SELECT name,age FROM jedis_table", 
 resultClass = Jedi.class)

Тогда мы можем просто сделать:

TypedQuery<jedi> query = em.createNamedQuery("jedisQry", Jedi.class);
List<jedi> items = query.getResultList();
</jedi></jedi>

Это безопаснее, но мы по-прежнему ограничены в использовании сопоставленной сущности.

Ручное картографирование

Решение, которое я немного экспериментировал (до появления JPA 2.1), заключалось в отображении конструктора POJO с использованием небольшого отражения.

public static <t> T map(Class<t> type, Object[] tuple){
   List<class<?>> tupleTypes = new ArrayList<>();
   for(Object field : tuple){
      tupleTypes.add(field.getClass());
   }
   try {
      Constructor<t> ctor = type.getConstructor(tupleTypes.toArray(new Class<!--?-->[tuple.length]));
      return ctor.newInstance(tuple);
   } catch (Exception e) {
      throw new RuntimeException(e);
   }
}
</t></class<?></t></t>

Этот метод в основном берет массив кортежей (как возвращено нативными запросами) и сопоставляет его с предоставленным классом POJO, ища конструктор, который имеет такое же количество полей и того же типа.

Тогда мы можем использовать удобные методы, такие как:

public static <t> List<t> map(Class<t> type, List<object[]> records){
   List<t> result = new LinkedList<>();
   for(Object[] record : records){
      result.add(map(type, record));
   }
   return result;
}

public static <t> List<t> getResultList(Query query, Class<t> type){
  @SuppressWarnings("unchecked")
  List<object[]> records = query.getResultList();
  return map(type, records);
}
</object[]></t></t></t></t></object[]></t></t></t>

И мы можем просто использовать эту технику следующим образом:

Query query = em.createNativeQuery("SELECT name,age FROM jedis_table");
List<jedi> jedis = getResultList(query, Jedi.class);
</jedi>

JPA 2.1 с @SqlResultSetMapping

С появлением JPA 2.1 мы можем использовать аннотацию @SqlResultSetMapping для решения проблемы.

Нам нужно объявить отображение набора результатов где-нибудь в сущности:

@SqlResultSetMapping(name="JediResult", classes = {
    @ConstructorResult(targetClass = Jedi.class, 
    columns = {@ColumnResult(name="name"), @ColumnResult(name="age")})
})

И тогда мы просто делаем:

Query query = em.createNativeQuery("SELECT name,age FROM jedis_table", "JediResult");
@SuppressWarnings("unchecked")
List<jedi> samples = query.getResultList();
</jedi>

Конечно, в этом случаеJedi не должен быть сопоставленным объектом. Это может быть обычный POJO.

Использование XML Mapping

Я один из тех, кто находит добавление всех этих@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>

<sql-result-set-mapping name="JediMapping">
        <constructor-result target-class="org.answer.model.Jedi">
            <column name="name" class="java.lang.String">
            <column name="age" class="java.lang.Integer">
        </column></column></constructor-result>
    </sql-result-set-mapping>

И это все решения, которые я знаю. Последние два являются идеальным способом, если мы можем использовать JPA 2.1.

 chrismarx22 окт. 2015 г., 21:47
Возможно ли для конструктора результата использовать класс, который имеет вложенный класс?
 Paul Bastide12 мая 2016 г., 20:30
Если бы я мог дать вам больше кредитов, я бы сделал.
 Alboz20 апр. 2015 г., 17:36
Что вы подразумеваете под "где-то в сущности ? Мой Пойо не может JPAt Я объявляю @SqlResultSetMapping в моем POJO? Я'Я заинтересован в решениях JPA 2.1. Пожалуйста, будьте немного точнее.
 alexander27 авг. 2016 г., 19:05
Я только что обновил до JPA 2.1 и использовал ваш путь. Отлично работает.
 Sunnyday19 янв. 2018 г., 23:03
@fjkjava не понимаю. Собственный запрос и запрос хранимой процедуры - это две вещи, верно?
 FilipeCanatto10 окт. 2018 г., 13:25
Можете ли вы привести пример того, как будет конструктор класса джедаев?
 fjkjava08 сент. 2016 г., 00:03
Я видел это, но мне не нравится это в xml, нет конфигов xml в моем приложении, почему я могуОни позволяют нам использовать это как часть StoredProcedureQuery или @Repository
 MaNn27 нояб. 2015 г., 07:43
@EdwinDalorzo Люблю тебя за это :) Мне очень помогли
 fjkjava07 сент. 2016 г., 21:47
Мне не нравится это решение, потому что вам нужно добавить @SqlResultSetMapping и сущность, которая может не иметь никакого отношения к pojo.
 Thomas06 июл. 2016 г., 12:31
Я хочу добавить, что ResultSetMapping не работает с Long вместо POJO. Может быть, связано с Гленномкомментарий о требовании конструктора.
 xyz17 мар. 2015 г., 10:51
Как мы можем отобразить набор результатов для аннотации @Query?
 Glenn20 апр. 2016 г., 05:49
При использовании JPA 2.1 с@SqlResultSetMapping возможно, стоит отметить, чтоJedi класс потребует конструктор всех аргументов и@ColumnResult аннотация может понадобитьсяtype Атрибут добавлен в преобразования, которые могут быть неявными (мне нужно было добавитьtype = ZonedDateTime.class для некоторых столбцов).
 Edwin Dalorzo20 апр. 2015 г., 17:40
@Alboz The@SqlResultSetMapping должны быть помещены в объект, потому что этос чего JPA будет читать метаданные. Вы не можете ожидать, что JPA будет проверять ваши POJO. Объект, в который вы помещаете отображение, не имеет значения, возможно, тот, который больше связан с вашими результатами POJO. В качестве альтернативы отображение может быть выражено в XML, чтобы избежать связи с совершенно не связанной сущностью.
 alexander27 авг. 2016 г., 11:26
Я всегда получаюДля этого имени не определен запрос ", Я только что скопировал твой пример. Я использую JPA 2.0. У вас есть какие-либо подсказки?
 pablorc05 сент. 2016 г., 03:29
К этому ответу можно быстро добавить следующее: если вы используете Spring для подключения EntityManager, вы можете сказать ему прочитать файл ORM XML. <bean id = "myEntityManagerFactory»               класс =»org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean ">         <имя свойства = "источник данных" исх =»myDataSource "/>         <имя свойства = "packagesToScan» значение =»модель "/>         <имя свойства = "mappingResources» значение =»META-INF / orm.xml "/>         ... </ Фасоль>
 Edwin Dalorzo07 сент. 2016 г., 23:55
@fjkjava Если бы вы прочитали весь ответ, вы бы заметили, что последний раздел посвящен именно этой проблеме.
 membersound19 сент. 2014 г., 11:45
Sidenote: Я только что использовал подход JPA 2.0 с зависимостью JPA2.1, и он потерпел неудачу. Так что, вероятно, это не совместимо вниз ...

Это легко. У вас есть очень полезные аннотации. Они упрощают вашу жизнь.

Сначала объявите свой собственный запрос, а затем сопоставление набора результатов (которое определяет отображение данных, возвращаемых базой данных в ваши POJO). Напишите ваш класс POJO для ссылки (не включен здесь для краткости). И последнее, но не менее важное: создайте метод в DAO (например) для вызова запроса. Это работало для меня в приложении dropwizard (1.0.0).

Сначала объявите собственный запрос в классе сущности:

@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());
    }
</domain.io.mymapping>

Тот'сидеть.

 Arnab Dutta22 мар. 2018 г., 21:26
Я вижу еще одну горькую правду: NamedNativeQuery & SqlResultSetMapping должен находиться в классе @Entity
 mwatzer17 сент. 2017 г., 15:10
Хороший ответ, но я думаю, что вы пропустили скобки после первой аннотации @ColumnResult.
 Zbyszek21 февр. 2018 г., 09:12
В коде есть ошибки, но их легко исправить. Например: "resulSetMapping = " должно быть "resultSetMapping = "

в не-сущности (то есть Beans / POJO). Процедура заключается в следующем.

List<jobdto> dtoList = entityManager.createNativeQuery(sql)
        .setParameter("userId", userId)
        .unwrap(org.hibernate.Query.class).setResultTransformer(Transformers.aliasToBean(JobDTO.class)).list();
</jobdto>

Использование для реализации JPA-Hibernate.

 Lu5514 июн. 2018 г., 13:53
Обратите внимание, чтоJobDTO должен иметь конструктор по умолчанию. Или вы можете реализовать свой собственный трансформатор на основеAliasToBeanResultTransformer реализация.

Query query = getCurrentSession().createSQLQuery(sqlQuery).addEntity(Actors.class);
List<actors> list = (List<actors>) query.list();
return list;
</actors></actors>

public class User2DTO implements Serializable {

    /** pode ser email ou id do Google comecando com G ou F para Facebook */
    private String username;

    private String password;

    private String email;

    private String name;

    private Integer loginType;

    public User2DTO(Object...fields) {
        super();
        this.username = (String) fields[0];
        this.name = (String) fields[1];
        this.email = (String) fields[2];
        this.password = (String) fields[3];
        this.loginType = (Integer) fields[4];
    }

и назовите это:

EntityManager em = repo.getEntityManager();
        Query q = em.createNativeQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u");
        List<object[]> objList = q.getResultList();
        List<user2dto> ooBj = objList.stream().map(User2DTO::new).collect(Collectors.toList());
</user2dto></object[]>

подходит ли это здесь, но у меня был похожий вопрос и я нашел следующее простое решение / пример для меня:

private EntityManager entityManager;
...
    final String sql = " SELECT * FROM STORE "; // select from the table STORE
    final Query sqlQuery = entityManager.createNativeQuery(sql, Store.class);

    @SuppressWarnings("unchecked")
    List<store> results = (List<store>) sqlQuery.getResultList();
</store></store>

В моем случае мне пришлось использовать части SQL, определенные в строках где-то еще, поэтому я не мог просто использовать NamedNativeQuery.

 Olgun Kaya10 мар. 2019 г., 15:52
как только мы возвращаемся. ничего фантастического. проблема в том, когда вы пытаетесь сопоставить результат с неуправляемым POJO.

Сначала объявите следующие аннотации:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NativeQueryResultEntity {
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NativeQueryResultColumn {
    int index();
}

Затем аннотируйте ваш POJO следующим образом:

@NativeQueryResultEntity
public class ClassX {
    @NativeQueryResultColumn(index=0)
    private String a;

    @NativeQueryResultColumn(index=1)
    private String b;
}

Затем напишите аннотацию процессора:

public class NativeQueryResultsMapper {

    private static Logger log = LoggerFactory.getLogger(NativeQueryResultsMapper.class);

    public static <t> List<t> map(List<object[]> objectArrayList, Class<t> genericType) {
        List<t> ret = new ArrayList<t>();
        List<field> mappingFields = getNativeQueryResultColumnAnnotatedFields(genericType);
        try {
            for (Object[] objectArr : objectArrayList) {
                T t = genericType.newInstance();
                for (int i = 0; i < objectArr.length; i++) {
                    BeanUtils.setProperty(t, mappingFields.get(i).getName(), objectArr[i]);
                }
                ret.add(t);
            }
        } catch (InstantiationException ie) {
            log.debug("Cannot instantiate: ", ie);
            ret.clear();
        } catch (IllegalAccessException iae) {
            log.debug("Illegal access: ", iae);
            ret.clear();
        } catch (InvocationTargetException ite) {
            log.debug("Cannot invoke method: ", ite);
            ret.clear();
        }
        return ret;
    }

    // Get ordered list of fields
    private static <t> List<field> getNativeQueryResultColumnAnnotatedFields(Class<t> genericType) {
        Field[] fields = genericType.getDeclaredFields();
        List<field> orderedFields = Arrays.asList(new Field[fields.length]);
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].isAnnotationPresent(NativeQueryResultColumn.class)) {
                NativeQueryResultColumn nqrc = fields[i].getAnnotation(NativeQueryResultColumn.class);
                orderedFields.set(nqrc.index(), fields[i]);
            }
        }
        return orderedFields;
    }
}
</field></t></field></t></field></t></t></t></object[]></t></t>

Используйте вышеуказанные рамки следующим образом:

String sql = "select a,b from x order by a";
Query q = entityManager.createNativeQuery(sql);

List<classx> results = NativeQueryResultsMapper.map(q.getResultList(), ClassX.class);
</classx>

org.springframework.jdbc.core.RowMapper

Вот пример:

public List query(String objectType, String namedQuery)
{
  String rowMapper = objectType + "RowMapper";
  // then by reflection you can instantiate and use. The RowMapper classes need to follow the naming specific convention to follow such implementation.
} 

Использование Hibernate:

@Transactional(readOnly=true)
public void accessUser() {
EntityManager em = repo.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    org.hibernate.SQLQuery q = (org.hibernate.SQLQuery) session.createSQLQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u").addScalar("username", StringType.INSTANCE).addScalar("name", StringType.INSTANCE).addScalar("email", StringType.INSTANCE).addScalar("passe", StringType.INSTANCE).addScalar("loginType", IntegerType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(User2DTO.class));

    List<user2dto> userList = q.list();
}
</user2dto>

Старый стиль с использованием ResultSet

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = this.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    session.doWork(new Work() {
        @Override
        public void execute(Connection con) throws SQLException {
            try (PreparedStatement stmt = con.prepareStatement(
                    "SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")) {
                ResultSet rs = stmt.executeQuery();
                ResultSetMetaData rsmd = rs.getMetaData();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    System.out.print(rsmd.getColumnName(i) + " (" + rsmd.getColumnTypeName(i) + ") / ");
                }
                System.out.println("");
                while (rs.next()) {
                    System.out.println("Found username " + rs.getString("USERNAME") + " name " + rs.getString("NAME") + " email " + rs.getString("EMAIL") + " passe " + rs.getString("PASSE") + " email " + rs.getInt("LOGIN_TYPE"));
                }
            }
        }
    });
}

DTO Design Pattern, Он был использован вEJB 2.0, Объект был управляемым контейнером.DTO Design Pattern используется для решения этой проблемы. Но это может быть использовано сейчас, когда приложение разрабатываетсяServer Side а такжеClient Side по отдельности.DTO используется когдаServer side Безразлично»не хочу проходить / возвращатьсяEntity с аннотацией к.Client Side

Пример DTO:

PersonEntity.java

@Entity
public class PersonEntity {
    @Id
    private String id;
    private String address;

    public PersonEntity(){

    }
    public PersonEntity(String id, String address) {
        this.id = id;
        this.address = address;
    }
    //getter and setter

}

PersonDTO.java

public class PersonDTO {
    private String id;
    private String address;

    public PersonDTO() {
    }
    public PersonDTO(String id, String address) {
        this.id = id;
        this.address = address;
    }

    //getter and setter 
}

DTOBuilder.java

public class DTOBuilder() {
    public static PersonDTO buildPersonDTO(PersonEntity person) {
        return new PersonDTO(person.getId(). person.getAddress());
    }
}

EntityBuilder.java <- это может быть необходимо

public class EntityBuilder() {
    public static PersonEntity buildPersonEntity(PersonDTO person) {
        return new PersonEntity(person.getId(). person.getAddress());
    }
}
 Gunjan Shah22 окт. 2012 г., 18:45
Спасибо за ответ. Здесь мне не нужен шаблон DTO. Мое требование - не скрывать детали аннотации от клиента. Поэтому мне не нужно создавать еще один POJO в моем приложении. Мое требование - привести результирующий набор к qa pojo, который не является сущностью JAVA, а простым классом POJO, который имеет те же поля, что и столбцы набора результатов.

Старый стиль с использованием Resultset

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = this.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    session.doWork(new Work() {
        @Override
        public void execute(Connection con) throws SQLException {
            try (PreparedStatement stmt = con.prepareStatement(
                    "SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")) {
                ResultSet rs = stmt.executeQuery();
                ResultSetMetaData rsmd = rs.getMetaData();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    System.out.print(rsmd.getColumnName(i) + " (" + rsmd.getColumnTypeName(i) + ") / ");
                }
                System.out.println("");
                while (rs.next()) {
                    System.out.println("Found username " + rs.getString("USERNAME") + " name " + rs.getString("NAME") + " email " + rs.getString("EMAIL") + " passe " + rs.getString("PASSE") + " email " + rs.getInt("LOGIN_TYPE"));
                }
            }
        }
    });
}
Решение Вопроса

SqlResultSetMapping это позволяет вам отображать любые результаты из вашего собственного запроса в сущностьили пользовательский класс.

РЕДАКТИРОВАТЬ JPA 1.0 не позволяет отображать классы, не связанные с сущностью. Только в JPA 2.1 aConstructorResult был добавлен к карте возвращаемых значений класс Java.

Также для ОП 'С проблемой получения количества должно быть достаточно для определения отображения набора результатов с помощью одногоColumnResult

 Edwin Dalorzo31 янв. 2014 г., 17:40
Я думаю, что @SqlResultSetMapping работает только с отображением сущностей, а не только с POJO.
 billschen14 дек. 2018 г., 02:54
Spring JPA 2.1, очень наглядный пример:github.com/spring-projects/spring-data-examples/tree/master/jpa/...
 Arnab Dutta22 мар. 2018 г., 21:35
Я вижу еще одну горькую правду: ConstructorResult может отображаться в POJO. НО ConstructorResult должен быть в классе Entity, чтобы вы могли Entity 'не избежать ... и, следовательно, более сложный факт: вам нужен какой-то результат сне волнует первичный ключ - все равно у вас должен быть @Id в Entity ... смешно, верно?
 FGreg30 янв. 2013 г., 22:43
Когда я попробовал это, я получил ошибку, что класс не был известным объектом. Я закончил тем, что использовал этот подходstackoverflow.com/questions/5024533/... вместо того, чтобы пытаться использовать собственный запрос.
 Denis Tulskiy22 окт. 2012 г., 19:04
@GunjanShah: лучший способ узнать это попробовать :) также, сущность - это то же самое pojo, только с некоторыми аннотациями. до тех пор, как вы'Если вы не будете настаивать на этом, он останется пижо.
 Gunjan Shah22 окт. 2012 г., 18:52
Спасибо за ответ. Здесь мы сопоставляем наш результат с сущностью с помощью класса сущности Java с помощью "@EntityResult» а также "@FieldResult» аннотаций. Все в порядке. Но здесь мне нужно больше ясности. Требуется ли, чтобы класс, который мы отображаем с результатом, был классом сущности JPA? ИЛИ мы можем использовать простой класс POJO, который не является покупкой сущности, который имеет все необходимые переменные в качестве столбцов в наборе результатов.
 Denis Tulskiy31 янв. 2014 г., 17:54
@EdwinDalorzo: этоПравильно для jpa 1.0. в jpa 2.1 онимы добавилиConstructorResult в качестве одного из параметровSqlResultSetMapping что позволяет использовать pojo со всеми полями, заданными в конструкторе. Я'уточню ответ.

я делюсь своим решением.

В моей ситуации сPostgres 9.4во время работы сJackson

//Convert it to named native query.
List<string> list = em.createNativeQuery("select cast(array_to_json(array_agg(row_to_json(a))) as text) from myschema.actors a")
                   .getResultList();

List<actorproxy> map = new ObjectMapper().readValue(list.get(0), new TypeReference<list<actorproxy>>() {});
</list<actorproxy></actorproxy></string>

Я уверен, что вы можете найти то же самое для других баз данных.

Также к вашему сведению,Собственные результаты запроса JPA 2.0 в виде карты

Spring-jpaЭто дополнение к ответам и на этот вопрос. Пожалуйста, исправьте это, если есть какие-либо недостатки. Я в основном использовал три метода для достижения "результат отображенияObject[] в пойо исходя из того, с какой практической потребностью я встречаюсь:

JPA встроенный метод достаточно.Встроенный метод JPA не достаточно, но настроенныйsql с этимиEntity достаточно.

Первый 2 не удалось, и я должен использоватьnativeQuery, Вот примеры. Пойо ожидал:

public class Antistealingdto {

    private String secretKey;

    private Integer successRate;

    // GETTERs AND SETTERs

    public Antistealingdto(String secretKey, Integer successRate) {
        this.secretKey = secretKey;
        this.successRate = successRate;
    }
}

Способ 1: Измените pojo на интерфейс:

public interface Antistealingdto {
    String getSecretKey();
    Integer getSuccessRate();
}

И хранилище:

interface AntiStealingRepository extends CrudRepository<antistealing, long=""> {
    Antistealingdto findById(Long id);
}
</antistealing,>

Способ 2: Хранилище:

@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 будет таким же, как он хранится (зашифрованный).

 Tiina09 июн. 2017 г., 09:20
@MartinVysny да, M1 - это JPQL. любые проекты, реализующие JPQL, должны его поддерживать. Таким образом, может быть, M2 также широко поддерживается?
 Martin Vysny08 июн. 2017 г., 18:20
Способ 1 неНа самом деле требуется Spring и работает с чистым Hibernate.

получения результата из собственного запроса без использования сложного 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.http://dev.mysql.com/doc/employee/en/employees-installation.html

persistence.xml

<!--?xml version="1.0" encoding="UTF-8"?--><persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1" xsi:schemalocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="jpa-mysql" transaction-type="RESOURCE_LOCAL">
    <class>org.moonwave.jpa.model.pojo.Employee</class>
    <properties>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/employees">
        <property name="javax.persistence.jdbc.user" value="user">
        <property name="javax.persistence.jdbc.password" value="***">
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver">
    </property></property></property></property></properties>
</persistence-unit>
</persistence>

Employee.java

package org.moonwave.jpa.model.pojo;

@Entity
public class Employee {

@Id
protected Long empNo;

protected String firstName;
protected String lastName;
protected String title;

public Long getEmpNo() {
    return empNo;
}
public void setEmpNo(Long empNo) {
    this.empNo = empNo;
}
public String getFirstName() {
    return firstName;
}
public void setFirstName(String firstName) {
    this.firstName = firstName;
}
public String getLastName() {
    return lastName;
}
public void setLastName(String lastName) {
    this.lastName = lastName;
}   
public String getTitle() {
    return title;
}
public void setTitle(String title) {
    this.title = title;
}
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("empNo: ").append(empNo);
    sb.append(", firstName: ").append(firstName);
    sb.append(", lastName: ").append(lastName);
    sb.append(", title: ").append(title);
    return sb.toString();
}
}

EmployeeNativeQuery.java

public class EmployeeNativeQuery {
private EntityManager em;
private EntityManagerFactory emf;

public void setUp() throws Exception {
    emf=Persistence.createEntityManagerFactory("jpa-mysql");
    em=emf.createEntityManager();
}
public void tearDown()throws Exception {
    em.close();
    emf.close();
}

@SuppressWarnings("unchecked")
public void query() {
    Query query = em.createNativeQuery("select e.emp_no as empNo, e.first_name as firstName, e.last_name as lastName," + 
            "t.title from employees e join titles t on e.emp_no = t.emp_no", Employee.class);
    query.setMaxResults(30);
    List<employee> list = (List<employee>) query.getResultList();
    int i = 0;
    for (Object emp : list) {
        System.out.println(++i + ": " + emp.toString());
    }
}

public static void main( String[] args ) {
    EmployeeNativeQuery test = new EmployeeNativeQuery();
    try {
        test.setUp();
        test.query();
        test.tearDown();
    } catch (Exception e) {
        System.out.println(e);
    }
}
}
</employee></employee>
 user31805418 мар. 2015 г., 11:02
Это не отвечает на вопрос, поскольку сущность JPA все еще требуется.
 Jonathan L26 янв. 2015 г., 19:33
Посмотрите на мой комментарий в Employee.java,A POJO used as pseudo entity to retrieve result from native query. This entity does not map to any physical table. Minimum annotations are @Enity and @Id ...  это освобождает пользователя от записиSqlResultSetMapping вещи. Этоpseudo entity который запрашивает JPA для загрузки этого класса, отображение таблицы не требуется, все необходимые поля
 Jonathan L23 янв. 2015 г., 18:52
@SuppressWarnings (»бесконтрольно») используется для подавления предупрежденияList list = (List) query.getResultList(); + Изменитьfor (Object emp : list) вfor (Employee emp : list) лучше, но без ошибок, если хранить какObject emp так как список является экземпляромList, Я изменил код в проекте git, но не здесь, чтобы ваш комментарий был актуален для исходного поста.
 Edwin Dalorzo23 янв. 2015 г., 19:04
проблема в том, что ваш запрос не возвращает список сотрудников, а представляет собой массив объектов. Ваше скрытое предупреждение скрывает это. В тот момент, когда вы пытаетесь преобразовать любого из них в сотрудника, вы получите ошибку, исключение приведения.
 Edwin Dalorzo22 янв. 2015 г., 12:42
Так как вашlist это, якобы, списокEmployeeпочему ваш цикл for-each повторяется над типомObject? Если вы напишите свой цикл for-each какfor(Employee emp : list) затем вы'обнаружил, что ваш ответ неверный, и содержимое вашего списка не является сотрудниками, и что это предупреждение, которое вы подавили, имело целью предупредить вас об этой потенциальной ошибке.
 Edwin Dalorzo23 янв. 2015 г., 22:08
О, я понимаю, что ты имеешь в виду сейчас. Но в этом случае ваш ответ не удовлетворяет вопросу, потому что речь шла об использовании обычного POJO в качестве целевого объекта, а ваш ответ используетEmployee который я предполагаю, является юридическим лицом. Isn»не так ли?
 Jonathan L23 янв. 2015 г., 22:05
смотреть наQuery query = em.createNativeQuery("select * ...", Employee.class); и persistence.xml, собственный запрос возвращает список Employee. Я только что проверил и запустил проект без проблемы. Если вы настроите пример базы данных mysql для сотрудников локально, вы также сможете запустить проект

Использование Hibernate:

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = repo.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    org.hibernate.SQLQuery q = (org.hibernate.SQLQuery) session.createSQLQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")
        .addScalar("username", StringType.INSTANCE).addScalar("name", StringType.INSTANCE)
        .addScalar("email", StringType.INSTANCE).addScalar("passe", StringType.INSTANCE)
        .addScalar("loginType", IntegerType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(User2DTO.class));

    List<user2dto> userList = q.list();
}
</user2dto>

Ваш ответ на вопрос