java - 如何以类型安全的方式运行 Hibernate NativeQuery 而不是返回 Object[]
问题描述
我正在将应用程序从 Hibernate 4.x 迁移到 Hibernate 5.3.6。该应用程序有这样的查询:
SQLQuery query = getSession().createSQLQuery("SELECT a.a, a.b, a.c FROM aTable");
由于createSQLQuery方法已被弃用,我首先将方法调用替换为 Hibernate Javadoc 中建议的替代方法,即使用 createNativeQuery:
NativeQuery query = getSession().createNativeQuery("SELECT a.a, a.b, a.c FROM aTable");
问题在于它会产生编译器警告“NativeQuery 是原始类型。对泛型类型 NativeQuery 的引用应该被参数化”。此外,我当然想从类型化查询中受益,因为它们是可用的。所以我将查询更改为
NativeQuery<Object[]> query = getSession().createNativeQuery("SELECT a.a, a.b, a.c FROM aTable", Object[].class);
现在的问题是执行查询
List<Object[]> retList = query.list();
产生错误
javax.persistence.PersistenceException:org.hibernate.MappingException:未知实体:[Ljava.lang.Object;
研究这个问题似乎表明在使用类型化的本机查询时不可能使用非映射实体(这似乎是一个严重且不必要的限制,但我在这里离题了)。
问题:有什么方法可以执行原生 SQL 查询,使用 Hibernate 返回一个对象数组,而不会产生编译器警告,同时实现类型安全?如果没有,是否有任何明智的选择?
解决方案
这种预测有更好的替代方案,而不是默认的Object[]
.
您可以使用 JPA
javax.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();
您可以使用 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();
您还可以使用命名的本机查询:
List<PostDTO> postDTOs = entityManager .createNamedQuery("PostDTO") .setParameter( "fromTimestamp", Timestamp.from( LocalDateTime.of( 2016, 1, 1, 0, 0, 0 ) .toInstant( ZoneOffset.UTC ) )) .getResultList();
其中
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") } ) )
很酷,对吧?
推荐阅读
- angular - 迁移以用 `ngrxPush` 替换 `async` 管道
- javascript - JavsScript - 遍历嵌套数组
- python - groupby 和 agg 之后的行数
- javascript - 如何确定 HERE 中的地图类型(例如普通、卫星)?
- go - 如何使用 strings.Contains 从 Struct 返回特定项目
- java - Java中的合并排序越界异常
- python - 给定一个直方图作为列表,我怎样才能找到 Otsu 的方法?
- javascript - 如何从 chrome 扩展中读取页面内容
- python - 如何在自己的包中使用自己的 Python 包?ModuleNotFoundError:没有命名的模块
- python - 无法在 MDGridLayout 中添加 kivymd 的 MDTextField