您有很多选项可以将投影映射到 DTO 结果集:
使用 Tuple 和 JPQL 的 DTO 投影
List<Tuple> postDTOs = entityManager.createQuery("""
select
p.id as id,
p.title as title
from Post p
where p.createdOn > :fromTimestamp
""", Tuple.class)
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of(2016, 1, 1, 0, 0, 0)
.toInstant(ZoneOffset.UTC )))
.getResultList();
assertFalse(postDTOs.isEmpty());
Tuple postDTO = postDTOs.get(0);
assertEquals(
1L,
postDTO.get("id")
);
使用构造函数表达式和 JPQL 的 DTO 投影
List<PostDTO> postDTOs = entityManager.createQuery("""
select new com.vladmihalcea.book.hpjp.hibernate.query.dto.projection.jpa.PostDTO(
p.id,
p.title
)
from Post p
where p.createdOn > :fromTimestamp
""", PostDTO.class)
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
.toInstant( ZoneOffset.UTC ) ))
.getResultList();
您还可以从 JPA 构造函数表达式中省略 DTO 包名称,并通过其简单的 Java 类名称引用 DTO(例如,PostDTO https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/).
List<PostDTO> postDTOs = entityManager.createQuery("""
select new PostDTO(
p.id,
p.title
)
from Post p
where p.createdOn > :fromTimestamp
""", PostDTO.class)
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
.toInstant( ZoneOffset.UTC ) ))
.getResultList();
使用元组和本机 SQL 查询的 DTO 投影
Hibernate 5.2.11 中提供了这一功能,因此又多了一个升级的理由。
List<Tuple> postDTOs = entityManager.createNativeQuery("""
SELECT
p.id AS id,
p.title AS title
FROM Post p
WHERE p.created_on > :fromTimestamp
""", Tuple.class)
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
.toInstant( ZoneOffset.UTC ) ))
.getResultList();
使用 ConstructorResult 的 DTO 投影
如果我们使用相同的PostDTO
之前介绍过的类类型,我们必须提供以下内容@SqlResultSetMapping
:
@NamedNativeQuery(
name = "PostDTO",
query = """
SELECT
p.id AS id,
p.title AS title
FROM Post p
WHERE p.created_on > :fromTimestamp
""",
resultSetMapping = "PostDTO"
)
@SqlResultSetMapping(
name = "PostDTO",
classes = @ConstructorResult(
targetClass = PostDTO.class,
columns = {
@ColumnResult(name = "id"),
@ColumnResult(name = "title")
}
)
)
现在,名为本机查询的 SQL 投影执行如下:
List<PostDTO> postDTOs = entityManager.createNamedQuery("PostDTO")
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
.toInstant( ZoneOffset.UTC ) ))
.getResultList();
使用 ResultTransformer 和 JPQL 的 DTO 投影
这次,您的 DTO 需要具有 Hibernate 从底层 JDBC 填充的属性的设置器ResultSet
.
DTO 投影如下所示:
List<PostDTO> postDTOs = entityManager.createQuery("""
select
p.id as id,
p.title as title
from Post p
where p.createdOn > :fromTimestamp
""")
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ))
.unwrap( org.hibernate.query.Query.class )
.setResultTransformer( Transformers.aliasToBean( PostDTO.class ) )
.getResultList();
使用 ResultTransformer 和本机 SQL 查询的 DTO 投影
List postDTOs = entityManager.createNativeQuery("""
select
p.id as \"id\",
p.title as \"title\"
from Post p
where p.created_on > :fromTimestamp
""")
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ))
.unwrap( org.hibernate.query.NativeQuery.class )
.setResultTransformer( Transformers.aliasToBean( PostDTO.class ) )
.getResultList();