简介
在这篇文章中,我将解释Hibernate TupleTransformer是如何工作的,以及如何使用它来替代被废弃的ResultTransformer。
被废弃的ResultTransformer
在使用Hibernate 6之前, ResultTransformer是转换查询结果集的默认选项。
然而,从5.2开始,HibernateQuery 接口的setResultTransformer 方法被废弃了,即使当时没有提供替代方法。这个方法及其相关的ResultTransformer 接口被废弃的原因是,ResultTransformer 接口不是一个功能接口。
功能性接口提供了一个单一的抽象方法,可以在定义lambda表达式时使用。出于这个原因,传统的ResultTransformer 接口被分成了两个接口TupleTransformer 和ResultListTransformer ,如下图所示。

Hibernate TupleTransformer
TupleTransformer 定义了transformTuple 方法,如下图所示。
@Incubating
@FunctionalInterface
public interface TupleTransformer<T> {
/**
* Tuples are the elements making up each "row" of the query result.
* The contract here is to transform these elements into the final
* row shape.
*
* @param tuple The result elements
* @param aliases The result aliases ("parallel" array to tuple)
*
* @return The transformed row.
*/
T transformTuple(Object[] tuple, String[] aliases);
}
transformTuple 方法允许你在消耗一个给定的记录后,对JDBCResultSet 产生的默认Object[] 数组投影进行转换。
如何使用Hibernate TupleTransformer
例如,假设我们有以下Post 实体。
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
private Long id;
private String title;
@Column(name = "created_on")
private LocalDateTime createdOn;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_on")
private LocalDateTime updatedOn;
@Column(name = "updated_by")
private String updatedBy;
@Version
private Integer version;
}
而我们想执行下面的JPQL查询,它可以获取一个自定义的投影。
select
p.id,
p.title,
p.createdOn,
p.createdBy,
p.updatedOn,
p.updatedBy
from Post p
order by p.id
默认情况下,当执行上面的JPQL查询时,项目记录将被包裹在一个Object[] 阵列中。
List<Object[]> postRecords = entityManager.createQuery("""
select
p.id,
p.title,
p.createdOn,
p.createdBy,
p.updatedOn,
p.updatedBy
from Post p
order by p.id
""")
.getResultList();
然而,使用Object[] 数组投影的操作对开发人员来说并不方便,所以我们要将查询结果映射到以下的Java记录层次上。

为此,我们要使用一个TupleTransformer ,允许我们将默认的Object[] 阵列投影映射到PostRecord 对象上,像这样。
List<PostRecord> postRecords = entityManager.createQuery("""
select
p.id,
p.title,
p.createdOn,
p.createdBy,
p.updatedOn,
p.updatedBy
from Post p
order by p.id
""")
.unwrap(org.hibernate.query.Query.class)
.setTupleTransformer(
(tuple, aliases) -> {
int i =0;
return new PostRecord(
longValue(tuple[i++]),
stringValue(tuple[i++]),
new AuditRecord(
localDateTimeValue(tuple[i++]),
stringValue(tuple[i++]),
localDateTimeValue(tuple[i++]),
stringValue(tuple[i++])
)
);
}
)
.getResultList();
很酷,对吗?
总结
Hibernate 6提供了很多新功能,比如[SQM(Semantic Query Model)(https://vladmihalcea.com/hibernate-sqm-semantic-query-model/)或对窗口函数的支持。
新的HibernateTupleTransformer 应该被用来替代传统的ResultTransformer 的使用,因为被废弃的ResultTransformer 肯定会在未来的Hibernate版本中被移除。