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


当前回答

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

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。

其他回答

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

就是这样。

可以执行展开过程,将结果分配给非实体(即Beans/POJO)。操作步骤如下。

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

该用法用于JPA-Hibernate实现。

在这种情况下,使用“数据库视图”这样的实体也就是不可变实体是非常容易的。

正常的实体

@Entity
@Table(name = "people")
data class Person(
  @Id
  val id: Long = -1,
  val firstName: String = "",
  val lastName: String? = null
)

视图类实体

@Entity
@Immutable
@Subselect("""
select
    p.id,
    concat(p.first_name, ' ', p.last_name) as full_name
from people p
""")
data class PersonMin(
  @Id
  val id: Long,
  val fullName: String,
)

在任何存储库中,我们都可以像这样创建查询函数/方法:

@Query(value = "select p from PersonMin p")
fun findPeopleMinimum(pageable: Pageable): Page<PersonMin>

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

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

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