将Hibernate Query.list()转换为List<Type>的“正确”方法是什么?

2022-08-31 11:15:50

我是Hibernate的新手,我正在编写一个简单的方法来返回与特定过滤器匹配的对象列表。 似乎是一种自然的回归类型。List<Foo>

无论我做什么,我似乎都不能让编译器满意,除非我使用一个丑陋的.@SuppressWarnings

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class Foo {

    public Session acquireSession() {
        // All DB opening, connection etc. removed,
        // since the problem is in compilation, not at runtime.
        return null;
    }

    @SuppressWarnings("unchecked") /* <----- */

    public List<Foo> activeObjects() {
        Session s = acquireSession();
        Query   q = s.createQuery("from foo where active");
        return (List<Foo>) q.list();
    }
}

我想摆脱那个抑制警告。但是如果我这样做,我会收到警告

Warning: Unchecked cast from List to List<Foo>

(我可以忽略它,但我想首先不要得到它),如果我删除泛型以符合返回类型,我会收到警告.list()

Warning: List is a raw type. References to generic type List<E>
should be parameterized.

我注意到,这确实声明了一个 ;但它完全是一个不同的类型 - 返回 a 作为原始类型。我觉得奇怪的是,最近的Hibernate(4.0.x)不会实现参数化类型,所以我怀疑是我做错了什么。org.hibernate.mappingListQueryjava.util.List

它看起来非常像将Hibernate结果投射到对象列表,但在这里我没有“硬”错误(系统知道类型Foo,我不是使用SQLQuery而是直接查询)。所以没有喜悦。

我也看过Hibernate类演员例外,因为它看起来很有希望,但后来我意识到我实际上没有得到任何...我的问题只是一个警告 - 一种编码风格,如果你愿意的话。Exception

关于 jboss.org,Hibernate手册和几个教程的文档似乎没有详细涵盖该主题(或者我没有在正确的地方搜索?)。当他们进入细节时,他们使用动态铸造 - 这是在官方 jboss.org 网站上没有的教程上,所以我有点警惕。

代码一旦编译,运行时没有明显的问题...据我所知...然而;结果是预期的。

所以:我做对了吗?我是否错过了一些明显的东西?有没有“官方”或“推荐”的方法来做到这一点


答案 1

简短的回答是正确的方法。@SuppressWarnings

长答案,Hibernate从该方法返回原始值,请参阅此处。这不是Hibernate的错误或可以解决的问题,查询返回的类型在编译时是未知的。ListQuery.list

因此,当您编写

final List<MyObject> list = query.list();

你正在做一个不安全的投射从到 - 这是无法避免的。ListList<MyObject>

您无法安全地进行铸造,因为可以包含任何东西。List

使错误消失的唯一方法是更丑陋

final List<MyObject> list = new LinkedList<>();
for(final Object o : query.list()) {
    list.add((MyObject)o);
}

答案 2

解决方案是改用 TypedQuery。从 EntityManager 创建查询时,请按如下方式调用它:

TypedQuery<[YourClass]> query = entityManager.createQuery("[your sql]", [YourClass].class);
List<[YourClass]> list = query.getResultList(); //no type warning

对于命名查询、本机命名查询等,这同样有效。相应的方法与返回 vanilla 查询的方法具有相同的名称。只要您知道返回类型,就使用这个而不是查询。


推荐