JPA:如何将本机查询结果集转换为POJO类集合


173

我在我的项目中使用JPA。

我来到一个查询,其中我需要对五个表进行联接操作。因此,我创建了一个本机查询,该查询返回五个字段。

现在,我想将结果对象转换为包含相同五个String的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类吗?


检查此答案。它具有完整的答案:stackoverflow.com/a/50365522/3073945
Sajedul Karim博士

他使用的是jpa,而不是spring

Answers:


103

JPA提供了SqlResultSetMapping,可让您将本机查询的任何返回值映射到Entity或自定义类

EDIT JPA 1.0不允许映射到非实体类。仅在JPA 2.1中,添加了ConstructorResult来映射Java类的返回值。

另外,对于OP的计数问题,使用一个定义一个结果集映射就足够了 ColumnResult


1
谢谢回复。在这里,我们将结果映射到带有带有“ @EntityResult”和“ @FieldResult”注释的java实体类的实体。没关系。但在这里我需要更清楚。是否要求我们要与结果映射的类必须是JPA实体类?或者我们可以使用一个不是实体购买的简单POJO类,它具有所有必需的变量作为结果集中的列。
Gunjan Shah 2012年

1
@GunjanShah:最好的了解方法是尝试一下:)另外,一个实体就是相同的pojo,只是带有一些注释。只要您不打算坚持下去,它就会持续下去。
Denis Tulskiy 2012年

2
尝试此操作时,我收到一个错误,指出该类不是已知的实体。我最终使用了这种方法stackoverflow.com/questions/5024533/…而不是尝试使用本机查询。
FGreg 2013年

2
@EdwinDalorzo:正确的是jpa 1.0。在jpa 2.1中,它们已ConstructorResult作为参数之一添加,SqlResultSetMapping从而允许在构造函数中设置所有字段的情况下使用pojo。我将更新答案。
Denis Tulskiy 2014年

4
我看到了另一个痛苦的事实:ConstructorResult可以映射到POJO。但是,ConstructorResult本身必须位于Entity类中,因此Entity不能避免……因此,更大的困难是:不需要关心就需要一些结果到主键-您仍然必须在Entity中使用@Id ...荒谬的权利吗?
Arnab Dutta

208

我找到了一些解决方案。

使用映射实体(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必须是一个映射的实体类。

避免此处未经检查的警告的一种替代方法是使用命名的本机查询。因此,如果我们在实体中声明本机查询

@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();

这样比较安全,但是我们仍然被限制使用映射实体。

手动映射

我尝试了一下的解决方案(在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);
   }
}

此方法基本上采用一个元组数组(由本机查询返回),并通过查找具有相同字段数和相同类型的构造函数将其映射到提供的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);
}

我们可以简单地使用这种技术,如下所示:

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

具有@SqlResultSetMapping的JPA 2.1

随着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不必是映射实体。它可以是常规的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>

<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"/>
        </constructor-result>
    </sql-result-set-mapping>

这些都是我所知道的解决方案。如果可以使用JPA 2.1,则后两种方法是理想的方法。


1
旁注:我只是将JPA 2.0方法与JPA2.1依赖项一起使用,但失败了。所以可能这不是向下兼容的……
Membersound

1
“实体中的某处”是什么意思?我的Pojo不是JPA实体,我不能在POJO中声明@SqlResultSetMapping吗?我对JPA 2.1解决方案感兴趣。请更加精确。
Alboz 2015年

3
@Alboz @SqlResultSetMapping必须将其放置在实体中,因为这是JPA将从中读取元数据的内容。您不能期望JPA检查您的POJO。您放置映射的实体无关紧要,也许是与POJO结果更相关的实体。或者,可以用XML表示映射,以避免与完全不相关的实体耦合。
Edwin Dalorzo

1
构造函数结果是否可以使用具有嵌套类的类?
chrismarx

5
如果将JPA 2.1与之配合使用,@SqlResultSetMapping则可能值得注意的是,Jedi该类将需要一个all-arg构造函数,并且@ColumnResult注释可能需要将type属性添加到可能不是隐式的转换中(我需要在type = ZonedDateTime.class某些列中添加 )。
Glenn

11

是的,有了JPA 2.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());
    }

而已。


好的答案,但是我认为您在第一个@ColumnResult批注之后错过了括号。
mwatzer

代码中有错误,但易于纠正。例如:“ resulSetMapping =“应该为” resultSetMapping =“
Zbyszek

3
我看到了另一个痛苦的事实:NamedNativeQuery和SqlResultSetMapping必须在@Entity类中
Arnab Dutta

10

如果使用Spring-jpa,这是对答案和此问题的补充。如果有任何缺陷,请更正此错误。我主要Object[]根据满足的实际需求使用了三种方法来实现“将结果映射到pojo”:

  1. JPA内置方法就足够了。
  2. JPA内置的方法还不够,但是sql使用其Entity进行定制即可。
  3. 前2个失败,我必须使用nativeQuery。这里是例子。pojo预期:

    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);
}

方法2:储存库:

@Query("select new AntistealingDTO(secretKey, successRate) from Antistealing where ....")
Antistealing whatevernamehere(conditions);

注意:POJO构造函数的参数序列在POJO定义和sql中必须相同。

方法3:使用@SqlResultSetMapping@NamedNativeQueryEntity在埃德温Dalorzo的答案的例子。

前两个方法将调用许多中间处理程序,例如定制的转换器。例如,AntiStealing定义一个secretKey,然后将其持久保存,然后插入转换器以对其进行加密。这将导致前2个方法返回转换后的结果secretKey,这不是我想要的。虽然方法3将克服转换器的问题,但返回的结果secretKey将与存储的结果相同(加密的结果)。


方法1实际上并不需要Spring,并且可以使用纯Hibernate。
Martin Vysny

@MartinVysny是的,M1是JPQL。任何实施JPQL的项目都应该支持它。这样,也许M2也得到了广泛支持?
蒂娜(Tiina)

8

可以执行解包过程以将结果分配给非实体(即Beans / POJO)。步骤如下。

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

该用法用于JPA-Hibernate实现。


请注意,JobDTO应具有默认构造函数。或者您可以根据AliasToBeanResultTransformer实现来实现自己的转换器。
Lu55

4

首先声明以下注释:

@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;
    }
}

使用上述框架,如下所示:

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

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

哪个包裹BeanUtils在里面?
哈里什

4

最简单的方法是使用投影。它可以将查询结果直接映射到接口,并且比使用SqlResultSetMapping易于实现。

一个例子如下所示:

@Repository
public interface PeopleRepository extends JpaRepository<People, Long> {

    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
        "FROM people p INNER JOIN dream_people dp " +
        "ON p.id = dp.people_id " +
        "WHERE p.user_id = :userId " +
        "GROUP BY dp.people_id " +
        "ORDER BY p.name", nativeQuery = true)
    List<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId);

    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
        "FROM people p INNER JOIN dream_people dp " +
        "ON p.id = dp.people_id " +
        "WHERE p.user_id = :userId " +
        "GROUP BY dp.people_id " +
        "ORDER BY p.name", nativeQuery = true)
    Page<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId, Pageable pageable);

}



// Interface to which result is projected
public interface PeopleDTO {

    String getName();

    Long getCount();

}

投影接口中的字段必须与此实体中的字段匹配。否则,字段映射可能会中断。

同样,如果使用SELECT table.column符号,请始终定义与实体名称匹配的别名,如示例所示。


1
本机查询和预测不能很好地结合在一起。
凯文·拉夫

1
我无法使字段映射正常工作-大多数值一直返回为空
ayang

3

在休眠状态下,您可以使用此代码轻松映射本机查询。

private List < Map < String, Object >> getNativeQueryResultInMap() {
String mapQueryStr = "SELECT * FROM AB_SERVICE three ";
Query query = em.createNativeQuery(mapQueryStr);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List < Map < String, Object >> result = query.getResultList();
for (Map map: result) {
    System.out.println("after request  ::: " + map);
}
return result;}

2

使用休眠:

@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();
}

2

使用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"));
                }
            }
        }
    });
}

1

由于其他人已经提到了所有可能的解决方案,因此我将分享我的解决方法。

在我的情况有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>>() {});

我相信您可以在其他数据库中找到相同的内容。

还提供FYI,JPA 2.0本机查询结果作为地图


1

不知道这是否适合这里,但是我有类似的问题,并为我找到了以下简单的解决方案/示例:

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();

在我的情况下,我必须使用在字符串中其他地方定义的SQL部分,所以我不能只使用NamedNativeQuery。


我们尽快返回实体。没有什么花哨。问题是当您尝试将结果映射到非托管POJO时。
Olgun Kaya

1

使用结果集的旧样式

@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"));
                }
            }
        }
    });
}

1

我们已通过以下方式解决了该问题:

   //Add actual table name here in Query
    final String sqlQuery = "Select a.* from ACTORS a"
    // add your entity manager here 
    Query query = entityManager.createNativeQuery(sqlQuery,Actors.class);
    //List contains the mapped entity data.
    List<Actors> list = (List<Actors>) query.getResultList();

0

请参见下面的示例,该示例使用POJO作为伪实体从本机查询中检索结果,而无需使用复杂的SqlResultSetMapping。在POJO中只需要两个注释,一个裸露的@Enity和一个假@Id。@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" />
    </properties>
</persistence-unit>

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);
    }
}
}

1
既然您list据称是的列表Employee,为什么您的for-each循环遍历类型Object?如果按如下方式编写for-each循环,for(Employee emp : list)则会发现您的答案是错误的,并且列表的内容不是员工,并且被抑制的警告旨在提醒您有关此潜在错误的信息。
Edwin Dalorzo

@SuppressWarnings(“未登记”),用于为抑制警告 List<Employee> list = (List<Employee>) query.getResultList();更改for (Object emp : list)for (Employee emp : list)是好,但如果没有错误保持原样Object emp,因为名单的一个实例List<Employee>。我更改了git项目中的代码,但未在此处保留您的评论与原始帖子相关的信息
Jonathan L

问题是您的查询不返回雇员列表,而是一个对象数组。您被压制的警告掩盖了这一点。当您尝试将其中任何一个转换为雇员时,您将得到一个错误,一个强制转换异常。
Edwin Dalorzo

查看Query query = em.createNativeQuery("select * ...", Employee.class);和persistence.xml,本机查询确实返回Employee列表。我刚刚签出并运行该项目,但没有问题。如果您在本地设置mysql示例雇员数据库,则您也应该能够运行该项目
Jonathan L

哦,我明白你的意思了。但是在那种情况下,您的答案不能满足问题,因为这是关于使用常规POJO作为目标对象,而您的答案是使用Employee我假设是实体的。是不是
Edwin Dalorzo 2015年

0

如果您使用的是Spring,则可以使用 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.
} 

0

使用休眠:

@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();
}

-1

将SQL查询转换为POJO类集合的简单方法,

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

-1

您需要的是带有构造函数的DTO:

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());

添加新列,代码将中断。

-2

使用DTO Design Pattern。它用于中EJB 2.0。实体由容器管理。DTO Design Pattern用于解决此问题。但是,它可能是使用现在,当应用程序开发Server SideClient Side分开。DTOServer 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());
    }
}

4
感谢您的回答。这里我不需要DTO模式。我的要求是不要从客户端隐藏注释详细信息。因此,我不需要在我的应用程序中再创建一个POJO。我的要求是将结果集转换为qa pojo,它不是JAVA实体,而是具有与结果集列相同字段的简单POJO类。
Gunjan Shah 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.