java - 将Hibernate Query.list()强制转换为List 的“正确”方法是什么?
我是Hibernate的新手,我正在写一个简单的方法来返回一个对象列表匹配特定的过滤器。 List似乎是一种自然的回归类型。
无论我做什么,我似乎都无法让编译器高兴,除非我使用了一个丑陋的Exception。
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 activeObjects() {
Session s = acquireSession();
Query q = s.createQuery("from foo where active");
return (List) q.list();
}
}
我想摆脱Exception.但如果我这样做,我会收到警告
Warning: Unchecked cast from List to List
(我可以忽略它,但我想首先得不到它),如果我删除通用符合Exception返回类型,我收到警告
Warning: List is a raw type. References to generic type List
should be parameterized.
我注意到Exception确实声明了List; 但它是一个完全不同的类型 - Query返回java.util.List,作为原始类型。 我觉得很奇怪,最近的Hibernate(4.0.x)不会实现参数化类型,所以我怀疑是我做错了。
它看起来非常像Cast Hibernate结果到一个对象列表,但在这里我没有“硬”错误(系统知道类型Foo,我不是使用SQLQuery而是直接查询)。 所以没有快乐。
我也看过Hibernate Class Cast Exception,因为它看起来很有前途,但后来我意识到我实际上并没有得到任何Exception ...我的问题只是一个警告 - 一种编码风格,如果你愿意的话。
关于jboss.org,Hibernate手册和几个教程的文档似乎没有详细介绍这个主题(或者我没有在正确的位置搜索?)。 当他们确实进入细节时,他们会使用即时投射 - 这是在官方jboss.org网站上没有的教程,所以我有点谨慎。
代码一经编译就没有明显的问题......我知道...... 结果是预期的结果。
那么:我这样做对吗? 我错过了一些明显的东西吗 有没有“官方”或“推荐”的方式吗?
9个解决方案
92 votes
简短的回答List是正确的方法。
答案很长,Hibernate从List方法返回原始List,请看这里。 这不是Hibernate的错误或可以解决的问题,查询返回的类型在编译时是未知的。
因此当你写作
final List list = query.list();
你正在做一个不安全的演员,从List到List - 这是无法避免的。
由于List可能包含任何内容,因此无法安全地执行演员表。
让错误消失的唯一方法就是更难看
final List list = new LinkedList<>();
for(final Object o : query.list()) {
list.add((MyObject)o);
}
Boris the Spider answered 2019-05-17T06:57:05Z
14 votes
解决方案是使用TypedQuery。 从EntityManager创建查询时,请调用它:
TypedQuery query = entityManager.createQuery("[your sql]", [YourClass].class);
List list = query.getResultList(); //no type warning
对于命名查询,本机命名查询等,这也是相同的。相应的方法与返回vanilla查询的方法具有相同的名称。 只要知道返回类型,就可以使用它而不是Query。
Taugenichts answered 2019-05-17T06:57:38Z
6 votes
您可以使用类似这样的解决方法来避免编译器警告:
List> resultRaw = query.list();
List result = new ArrayList(resultRaw.size());
for (Object o : resultRaw) {
result.add((MyObj) o);
}
但是这段代码存在一些问题:
创建了多余的ArrayList
对查询返回的所有元素进行不必要的循环
更长的代码。
差别只是装饰性的,所以使用这样的解决方法 - 在我看来 - 毫无意义。
你必须忍受这些警告或抑制它们。
Grzegorz Olszewski answered 2019-05-17T06:58:45Z
2 votes
要回答你的问题,没有“正确的方法”来做到这一点。现在,如果它只是困扰你的警告,避免其扩散的最好方法是将@SuppressWarnings("unchecked")方法包装到DAO中:
public class MyDAO {
@SuppressWarnings("unchecked")
public static List list(Query q){
return q.list();
}
}
这样你只能使用@SuppressWarnings("unchecked")一次。
Pdv answered 2019-05-17T06:59:19Z
2 votes
List list = new ArrayList();
Criteria criteria = this.getSessionFactory().getCurrentSession().createCriteria(Person.class);
for (final Object o : criteria.list()) {
list.add((Person) o);
}
user3184564 answered 2019-05-17T06:59:40Z
1 votes
你使用这样的ResultTransformer:
public List activeObjects() {
Session s = acquireSession();
Query q = s.createQuery("from foo where active");
q.setResultTransformer(Transformers.aliasToBean(Foo.class));
return (List) q.list();
}
lakreqta answered 2019-05-17T07:00:08Z
1 votes
对我来说唯一有效的方法就是迭代器。
Iterator iterator= query.list().iterator();
Destination dest;
ArrayList destinations= new ArrayList<>();
Iterator iterator= query.list().iterator();
while(iterator.hasNext()){
Object[] tuple= (Object[]) iterator.next();
dest= new Destination();
dest.setId((String)tuple[0]);
dest.setName((String)tuple[1]);
dest.setLat((String)tuple[2]);
dest.setLng((String)tuple[3]);
destinations.add(dest);
}
通过我发现的其他方法,我遇到了问题
Popa Andrei answered 2019-05-17T07:00:50Z
0 votes
正确的方法是使用Hibernate Transformers:
public class StudentDTO {
private String studentName;
private String courseDescription;
public StudentDTO() { }
...
}
。
List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();
StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);
迭代通过Object []是多余的,会有一些性能损失。有关变压器使用的详细信息,请访问:用于HQL和SQL的变换器
如果您正在寻找更简单的解决方案,您可以使用开箱即用的地图变换器:
List iter = s.createQuery(
"select e.student.name as studentName," +
" e.course.description as courseDescription" +
"from Enrolment as e")
.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP )
.iterate();
String name = (Map)(iter.next()).get("studentName");
ANTARA answered 2019-05-17T07:01:37Z
-1 votes
我在这里找到了最好的解决方案,这个问题的关键是addEntity方法
public static void testSimpleSQL() {
final Session session = sessionFactory.openSession();
SQLQuery q = session.createSQLQuery("select * from ENTITY");
q.addEntity(Entity.class);
List entities = q.list();
for (Entity entity : entities) {
System.out.println(entity);
}
}
Federico Traiman answered 2019-05-17T07:02:08Z