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


当前回答

如果你使用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.
} 

其他回答

最简单的方法就是使用投影。它可以将查询结果直接映射到接口,并且比使用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表。列表示法总是定义与实体名称匹配的别名,如示例所示。

JPA提供了一个SqlResultSetMapping,允许您将本地查询返回的任何内容映射到实体或自定义类。

EDIT JPA 1.0不允许映射到非实体类。只有在JPA 2.1中,才添加了一个ConstructorResult来映射java类的返回值。

同样,对于OP获取计数的问题,定义一个带有单个ColumnResult的结果集映射就足够了

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

在我使用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本机查询结果为映射

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

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

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。