如何以类型安全的方式运行 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 返回一个对象数组,而不会产生编译器警告?如果没有,是否有任何明智的选择?


潇潇雨雨
浏览 262回答 3
3回答

万千封印

这种投影有更好的替代方案,而不是默认的Object[]。您可以使用 JPAjavax.persistence.Tuple结果集,因为Hibernate ORM 5.2.11适用于本机 SQL:&nbsp;List<Tuple> postDTOs = entityManager&nbsp;.createNativeQuery(&nbsp; &nbsp; &nbsp;"SELECT " +&nbsp; &nbsp; &nbsp;"&nbsp; &nbsp; &nbsp; &nbsp;p.id AS id, " +&nbsp; &nbsp; &nbsp;"&nbsp; &nbsp; &nbsp; &nbsp;p.title AS title " +&nbsp; &nbsp; &nbsp;"FROM Post p " +&nbsp; &nbsp; &nbsp;"WHERE p.created_on > :fromTimestamp", Tuple.class)&nbsp;.setParameter( "fromTimestamp", Timestamp.from(&nbsp; &nbsp; &nbsp;LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.toInstant( ZoneOffset.UTC ) ))&nbsp;.getResultList();您可以使用 Hibernate-specific ResultTransformer,它允许您构建非常复杂的 DTO 结构(例如图形):&nbsp;List postDTOs = entityManager&nbsp;.createNativeQuery(&nbsp; &nbsp; &nbsp;"select " +&nbsp; &nbsp; &nbsp;"&nbsp; &nbsp; &nbsp; &nbsp;p.id as \"id\", " +&nbsp; &nbsp; &nbsp;"&nbsp; &nbsp; &nbsp; &nbsp;p.title as \"title\" " +&nbsp; &nbsp; &nbsp;"from Post p " +&nbsp; &nbsp; &nbsp;"where p.created_on > :fromTimestamp")&nbsp;.setParameter( "fromTimestamp", Timestamp.from(&nbsp; &nbsp; &nbsp;LocalDateTime.of( 2016, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ))&nbsp;.unwrap( org.hibernate.query.NativeQuery.class )&nbsp;.setResultTransformer( Transformers.aliasToBean( PostDTO.class ) )&nbsp;.getResultList();您还可以使用命名的本机查询:&nbsp;List<PostDTO> postDTOs = entityManager&nbsp;.createNamedQuery("PostDTO")&nbsp;.setParameter( "fromTimestamp", Timestamp.from(&nbsp; &nbsp; &nbsp;LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.toInstant( ZoneOffset.UTC ) ))&nbsp;.getResultList();其中PostDTO查询是一个命名的本机 SQL 查询,如下所示:&nbsp;@NamedNativeQuery(&nbsp; &nbsp; &nbsp;name = "PostDTO",&nbsp; &nbsp; &nbsp;query =&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"SELECT " +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"&nbsp; &nbsp; &nbsp; &nbsp;p.id AS id, " +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"&nbsp; &nbsp; &nbsp; &nbsp;p.title AS title " +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"FROM Post p " +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"WHERE p.created_on > :fromTimestamp",&nbsp; &nbsp; &nbsp;resultSetMapping = "PostDTO"&nbsp;)&nbsp;@SqlResultSetMapping(&nbsp; &nbsp; &nbsp;name = "PostDTO",&nbsp; &nbsp; &nbsp;classes = @ConstructorResult(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;targetClass = PostDTO.class,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;columns = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@ColumnResult(name = "id"),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@ColumnResult(name = "title")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp;)&nbsp;)酷,对吧?

慕慕森

只需通过调用创建它createNativeQuery("SELECT&nbsp;a.a,&nbsp;a.b,&nbsp;a.c&nbsp;FROM&nbsp;aTable");它将默认返回一行Object[].该警告与您的情况无关,因此只需将其压制即可。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java