createNativeQuery映射到POJO(非实体)

时间:2014-11-09 18:46:06

标签: java sql hibernate java-ee jpa

乍一看我有一个简单的问题:

entityManager()
.createNativeQuery("select count(*) as total, select sum(field) as total_sum ... blabla") 

我想将选择结果写入POJO,如下所示:

public class AggregateStatsDto {

    private int total;

    private long totalSum;

    // getters, setters, cosntructors
}

实现这一目标的最佳方法是什么?

我可以使用JPA 2.1并尝试将 @SqlResultSetMapping @ConstructorResult 结合使用:

@SqlResultSetMapping(name = "AggregateStatsResult", classes = {
        @ConstructorResult(targetClass = AggregateStatsDto.class,
                columns = {
                        @ColumnResult(name = "total"),
                        @ColumnResult(name = "totalSum")
                })
})
public class AggregateStatsDto {

        private long total;

        private int totalSum;

        // getters, setters, cosntructors
    }

查询:

AggregateStatsDto result = (AggregateStatsDto) entityManager()
    .createNativeQuery("select count(*) as total, select sum(field) as total_sum ... blabla", "AggregateStatsResult")
    .getSingleResult();

但没有运气。无论如何它似乎想要@Entity。但我只想要一个POJO。

org.hibernate.MappingException: Unknown SqlResultSetMapping [AggregateStatsResult]"

提前致谢!

7 个答案:

答案 0 :(得分:9)

将@SqlResultSetMapping批注放在一个实际实体的类中,而不是放在DTO类中。当您在非实体中注释SqlResultSetMapping时,您的实体管理器无法发现您的映射。

@SqlResultSetMapping(name = "AggregateStatsResult", classes = {
    @ConstructorResult(targetClass = AggregateStatsDto.class,
            columns = {
                    @ColumnResult(name = "total"),
                    @ColumnResult(name = "totalSum")
            })
})
@Entity
public class SomeOtherClassWhichIsAnEntity {

答案 1 :(得分:6)

我通过以下方式解决了我的问题: 这是一个查询:

  final Query query = Sale.entityManager().createNativeQuery(...);

然后我访问了实体管理器内部的Hibernate会话并应用了scalars / resultTransformer。多数民众赞成!

 // access to internal Hibernate of EntityManager
        query.unwrap(SQLQuery.class)
                .addScalar("total", LongType.INSTANCE)
                .addScalar("amountOfSales", LongType.INSTANCE)
                .addScalar("amountOfProducts", LongType.INSTANCE)
                .setResultTransformer(Transformers.aliasToBean(SaleStatsInfo.class));

        ...
        query.getSingleResult();

答案 2 :(得分:0)

这不是建议的方法。上面在@SqlResultSetMapping中提到了更有效的方法,但是如果您想要更硬的东西,则可以通过返回的对象访问实体管理器的结果。

例如:

 Query q = getEntityManager().createNativeQuery(queryString);

使用q.getSingleResult();触发该操作,将带回java.util.HashMap类型的对象,您可以使用它逐行访问结果。

例如:

    Query q = getEntityManager().createNativeQuery(queryString);
    java.util.HashMap res =  (java.util.HashMap) q.getSingleResult();
     for (Object key : res.keySet()) {
         System.out.println(key.toString());
         System.out.println( res.get(key).toString());
     }

答案 3 :(得分:0)

我被困了一段时间。我发现最常见的解决方案如下。不要忘记在createNativeQuery方法的第二个参数上添加映射的名称。这样,您的pojo应该没有注释,但将从实体类中进行映射。

//Place SqlResultSetMapping annotation in Entity class:

@SqlResultSetMapping(name = "AggregateStatsResult", classes = {
        @ConstructorResult(targetClass = AggregateStatsDto.class,
                columns = {
                        @ColumnResult(name = "total"),
                        @ColumnResult(name = "totalSum")
                })
})
@Entity
public EntityFromExistingTableInDB{
    ...fields
}

//1st param is your query, 2nd param is the name of your mapping above
Query query = entityManager.createNativeQuery("yourQuery", "AggregateStatsResult");

答案 4 :(得分:0)

我认为这是最直接的方法。

声明一个 POJO/DTO 并用 @NativeQueryResultEntity 标记它。注意我在这里使用 Lombok @Data 来声明 getter/setter。

import com.pls.core.jpa.nativequery.NativeQueryResultEntity;
import lombok.Data;

@Data
@NativeQueryResultEntity
public class FieldsDTO{

    @NativeQueryResultColumn(index = 0)
    private String fieldA;

    @NativeQueryResultColumn(index = 1)
    private String fieldB;
   
    @NativeQueryResultColumn(index = 2)
    private String fieldC;
}

然后使用 NativeQueryResultsMapper

String queryStr = "select field_a, field_b, field_c from db.table"
Query query = entityManager.createNativeQuery(queryStr);
List result = NativeQueryResultsMapper.map(query.getResultList(), FieldsDTO.class);

这就是你应该做的。 result 将是 FieldsDTO 个对象的列表。

答案 5 :(得分:-2)

如果你提供了一个合适的构造函数,Hibernate将填充任何pojo。

select new Pojo(p1, p2, p3,...) from entity)

将返回Pojo实例列表。

答案 6 :(得分:-3)

我在这个问题上苦苦挣扎,最后找到了一个很好的解决方案。

情况:我有一个本机查询,我只从数据库表中获取少数字段或所有字段,或者当我从表中获取数据时,我也可以对列进行一些操作。

现在我想将使用getResultList()方法得到的本地查询的输出映射到自己的POJO类/非JPA类中。 getResultList()的输出是一个对象列表,即List,因此我们需要手动循环并将值设置到我们的bean / pojo类中。查看下面的代码段。

所以我的查询就是这个 -

// This is your POJO/bean class where you have settter/getter 
// methods of values you want to fetch from the database
List<YourPOJO> yourPOJOList = new ArrayList<YourPOJO>();
YourPOJO pojo = null;

StringBuffer SQL = new StringBuffer();
// I am creating some random SQL query
SQL.append("SELECT tb1.col1, ");
SQL.append(" tb1.col2, ");
SQL.append(" tb2.col3, ");
SQL.append("FROM Table1 tb1, Table2 tb2 ");
SQL.append("WHERE tb1.ID = tb2.ID       ");

qry = getEntityManager().createNativeQuery(SQL.toString());
List<Object[]> cdList = qry.getResultList();

for(Object[] object : cdList){
pojo = new YourPojo();

// Here you manually obtain value from object and map to your pojo setters
pojo.setCode(object[0]!=null ? object[0].toString() : "");

pojo.setProductName(object[1]!=null ? object[1].toString() : "");

pojo.setSomeCode(object[2]!=null ? object[2].toString() : "");

yourPOJOList.add(pojo);
}
相关问题