我在我的项目中使用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类?


当前回答

既然其他人已经提到了所有可能的解决方案,我将分享我的变通方案。

在我使用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>>() {});

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

另供参考,JPA 2.0本机查询结果为映射

其他回答

如果您使用Spring-jpa,这是对答案和这个问题的补充。如有任何瑕疵,请改正。根据我的实际需求,我主要使用了三种方法来实现“map result Object[] to a pojo”:

JPA内置方法就足够了。 JPA内置的方法是不够的,但一个自定义的sql与它的实体是足够的。 前2失败,我必须使用一个nativeQuery。 下面是一些例子。 pojo期待着: 公共类 private String; private Integer successRate; // getter和setter public Antistealingdto(String secretKey, Integer successRate) { 这一点。secretKey = secretKey; 这一点。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: 在Edwin Dalorzo的回答中,以实体中的@SqlResultSetMapping和@NamedNativeQuery为例。

前两个方法将调用许多中间处理程序,如自定义转换器。例如,AntiStealing定义了一个secretKey,在它被持久化之前,会插入一个转换器来加密它。这将导致前2个方法返回一个转换后的返回secretKey,这不是我想要的。而方法3将克服转换器,返回的secretKey将与存储时相同(加密的)。

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

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

在上面的回答中,我尝试了很多事情。SQLmapper不知道该把它放在哪里。非托管pojo只是一个问题。我尝试了各种方法,其中一个简单的方法就是像往常一样。我使用的是hibernate-jpa-2.1。

List<TestInfo> testInfoList = factory.createNativeQuery(QueryConstants.RUNNING_TEST_INFO_QUERY)
                    .getResultList();

唯一需要注意的是POJO具有与查询相同的成员变量名(均为小写)。显然,我甚至不需要像在JPQL中使用TypedQueries那样告诉目标类和查询。

TestInfo.class

@Setter
@Getter
@NoArgsConstructor
@ToString
public class TestInfo {

    private String emailid;
    private Long testcount;

    public TestInfo(String emailId, Long testCount) {
        super();
        this.emailid = emailId;
        this.testcount = testCount;
    }

}

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

是的,使用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

下面你可以添加resultset映射声明:

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

就是这样。