我有一些非常复杂的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"?
答案 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 或使用字段创建新对象