Hibernate ResultTransformer无法转换单个列

时间:2015-10-28 13:36:42

标签: java hibernate

我有一些非常复杂的SQL(做一些聚合,一些基于最大值的计数等)所以我想使用SQLQuery而不是Query。我创建了一个非常简单的Pojo:

Y =

    1.2000    1.3000       NaN    0.9000    0.9500       NaN    0.8000    0.7000
idwinner =

   802   801   805   804

然后当我运行我的SQLQuery时,我希望hibernate为我填充List,所以我这样做:

public class SqlCount {
    private String name;
    private Double count;
    // getters, setters, constructors etc

现在我遇到了一个问题,取决于值是什么值'计数',Hibernate将可变地检索它为Long,Double,BigDecimal或BigInteger。所以我使用addScalar函数:

Query hQuery = sqlQuery.setResultTransformer(Transformers.aliasToBean(SqlCount.class));

现在我的问题。看来,如果你不使用addScalar函数,Hibernate会在你的SQL结果中填充所有列的所有字段(即它会尝试填充' name'和&## 39;计数&#39)。但是,如果使用addScalar函数,它只会映射您列出的列,并且所有其他列似乎都将被丢弃,并且字段保留为null。在这种情况下,仅列出" name"并不是太糟糕。并且"计算",但是我还有其他一些场景,我需要十几个字段 - 我真的要列出它们吗?在hibernate中是否有某种方式可以自动映射所有字段,就像过去一样,但是通过将此字段映射为Double"?

1 个答案:

答案 0 :(得分:1)

  

在休眠中是否有某种方式可以说“自动映射所有字段。

不,请查看文档here,找到 16.1.1。标量查询部分

  

最基本的SQL查询是获取标量列表(值)。

     

sess.createSQLQuery("SELECT * FROM CATS").list(); sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();

     

这些将返回一个对象数组列表(Object []),其中包含CATS表中每列的标量值。 Hibernate将使用ResultSetMetadata来推断返回的标量值的实际顺序和类型。   为了避免使用ResultSetMetadata的开销,或者只是在返回的内容中更明确,可以使用addScalar():

     

sess.createSQLQuery("SELECT * FROM CATS") .addScalar("ID", Hibernate.LONG) .addScalar("NAME", Hibernate.STRING) .addScalar("BIRTHDATE", Hibernate.DATE)

我使用此解决方案,希望它能与您合作。

使用此解决方案,您可以填充从SQL中选择的内容,并将其作为Map返回,并直接转换值。

因为hibernate 5.2方法 setResultTransformer()已被弃用,但它对我来说很好并且工作得很完美。

如果您不想为SQL中的每一列编写额外的代码 addScalar(),您可以实现 ResultTransformer接口并根据需要进行转换。

例如: 假设我们有这个查询:

/*ORACLE SQL*/

SELECT
  SEQ                 AS "code",
  CARD_SERIAL         AS "cardSerial",
  INV_DATE            AS "date",
  PK.GET_SUM_INV(SEQ) AS "sumSfterDisc"
FROM INVOICE
ORDER BY "code";

注意:对于区分大小写的列别名,我使用双cote,请检查This

创建hibernate会话后,您可以像这样创建Query:

/*Java*/

List<Map<String, Object>> list = session.createNativeQuery("SELECT\n" +
                    "  SEQ                 AS \"code\",\n" +
                    "  CARD_SERIAL         AS \"cardSerial\",\n" +
                    "  INV_DATE            AS \"date\",\n" +
                    "  PK.GET_SUM_INV(SEQ) AS \"sumSfterDisc\"\n" +
                    "FROM INVOICE\n" +
                    "ORDER BY \"code\"")
                    .setResultTransformer(new Trans())
                    .list();

现在点 Trans 类:

/*Java*/

public class Trans implements ResultTransformer {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);

    @Override
    public Object transformTuple(Object[] objects, String[] strings) {

        Map<String, Object> map = new LinkedHashMap<>();
        for (int i = 0; i < strings.length; i++) {

            if (objects[i] == null) {
                continue;
            }

            if (objects[i] instanceof BigDecimal) {
                map.put(strings[i], ((BigDecimal) objects[i]).longValue());
            } else if (objects[i] instanceof Timestamp) {
                map.put(strings[i], dateFormat.format(((Timestamp) objects[i])));
            } else {
                map.put(strings[i], objects[i]);
            }
        }
        return map;
    }

    @Override
    public List transformList(List list) {
        return list;
    }
}

这里你应该覆盖两个方法 transformTuple transformList ,在 transformTuple 你有两个参数 Object []对象行 String []的列值将列的名称 hibernate 保证与您在其中排序的列的顺序相同查询。

现在开始有趣了,对于从查询返回的每一行,将调用方法 transformTuple ,因此您可以将行构建为 Map 或使用字段创建新对象