sim*_*mon 8 java sql orm hibernate jpa
我正在将应用程序从 Hibernate 4.x 迁移到 Hibernate 5.3.6。该应用程序有这样的查询:
SQLQuery query = getSession().createSQLQuery("SELECT a.a, a.b, a.c FROM aTable");
Run Code Online (Sandbox Code Playgroud)
由于createSQLQuery方法已被弃用,我首先用 Hibernate Javadoc 中建议的替代方法替换了方法调用,即使用 createNativeQuery:
NativeQuery query = getSession().createNativeQuery("SELECT a.a, a.b, a.c FROM aTable");
Run Code Online (Sandbox Code Playgroud)
这样做的问题是它会产生一个编译器警告“NativeQuery 是原始类型。对泛型类型 NativeQuery 的引用应该被参数化”。此外,当然我想从类型化查询中受益,现在它们可用。所以我将查询更改为
NativeQuery<Object[]> query = getSession().createNativeQuery("SELECT a.a, a.b, a.c FROM aTable", Object[].class);
Run Code Online (Sandbox Code Playgroud)
现在的问题是执行查询
List<Object[]> retList = query.list();
Run Code Online (Sandbox Code Playgroud)
产生错误
javax.persistence.PersistenceException:org.hibernate.MappingException:未知实体:[Ljava.lang.Object;
研究这个问题似乎表明在使用类型化本机查询时不可能使用非映射实体(这似乎是一个严重且不必要的限制,但我在这里离题了)。
问题是:有没有什么方法可以在实现类型安全的同时执行本地 SQL 查询,使用 Hibernate 返回一个对象数组,而不会产生编译器警告?如果没有,是否有任何明智的选择?
Vla*_*cea 12
这种投影有更好的替代方案,而不是默认的Object[]。
您可以使用 JPAjavax.persistence.Tuple结果集,因为Hibernate ORM 5.2.11适用于本机 SQL:
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();
Run Code Online (Sandbox Code Playgroud)
您可以使用 Hibernate-specific ResultTransformer,它允许您构建非常复杂的 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();
Run Code Online (Sandbox Code Playgroud)
您还可以使用命名的本机查询:
List<PostDTO> postDTOs = entityManager
.createNamedQuery("PostDTO")
.setParameter( "fromTimestamp", Timestamp.from(
LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
.toInstant( ZoneOffset.UTC ) ))
.getResultList();
Run Code Online (Sandbox Code Playgroud)
其中PostDTO查询是一个命名的本机 SQL 查询,如下所示:
@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")
}
)
)
Run Code Online (Sandbox Code Playgroud)
酷,对吧?