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类?


JPA提供了一个SqlResultSetMapping ,它允许您将来自您的本机查询的任何回报映射到实体或自定义类中。

EDIT JPA 1.0不允许映射到非实体类。 只有在JPA 2.1中,ConstructorResult已被添加到映射返回值java类。

另外,对于OP的计数问题,它应该足以用一个ColumnResult定义一个结果集映射


我找到了几个解决方案。

使用映射实体(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);

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不需要是一个映射实体。 它可以是一个普通的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"/>
            <column name="age"/>
        </constructor-result>
    </sql-result-set-mapping>

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


是的,使用JPA 2.1很容易。 你有非常有用的注释。 他们简化你的生活。

首先声明你的本地查询,然后声明你的结果集映射。 写你的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());
    }

而已。

链接地址: http://www.djcxy.com/p/63699.html

上一篇: JPA : How to convert a native query result set to POJO class collection

下一篇: How to prevent scrolling while drawing inside Scrollview