Каков "правильный"способ выполнения запроса Hibernate.список() в список?
я новичок с 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();
}
}
я хотел бы избавиться от этой SuppressWarnings. Но если я это сделаю, я получу предупреждение
Warning: Unchecked cast from List to List<Foo>
(я могу игнорировать его, но я бы не получить его в первую очередь), и если я удалю общий, чтобы соответствовать .list() тип возврата, я получаю предупреждение
Warning: List is a raw type. References to generic type List<E>
should be parameterized.
я заметил, что org.hibernate.mappingтут объявления List; но это совершенно другой тип -Query возвращает a java.util.List, как необработанный тип. Мне кажется странным, что недавняя спячка (4.0.x) не будет реализовывать параметризованные типы, поэтому я подозреваю, что вместо этого я делаю что-то неправильно.
это очень похоже на приведите результат гибернации к списку объекты, но здесь у меня нет "жестких" ошибок (система знает тип Foo, и я не использую SQLQuery, но прямой запрос). Так что никакой радости.
я тоже посмотрел на Исключение Приведения Класса Hibernate так как это выглядело многообещающе, но потом я понял, что делаю не на самом деле вам любой Exception... моя проблема - это просто предупреждение-стиль кодирования, если хотите.
документация по jboss.org, спящий режим руководства и несколько учебников сделать не похоже, чтобы охватить тему в такие подробно (или я не искал в нужных местах?). Когда они входят в детали, они используют кастинг на лету - и это на учебниках, которые не были на официальном сайте jboss.org сайт, так что я немного насторожен.
код, после компиляции работает без видимого... это мне известно... тем не менее, и результаты являются ожидаемыми.
Итак: я делаю это право? Я упускаю что-то очевидное? Есть "официальный"
или "рекомендуется"Способ Сделать Это?
9 ответов:
короткий ответ:
@SuppressWarnings- это правильный путь.длинный ответ, Hibernate возвращает raw
ListСQuery.listметод, см. здесь. Это не ошибка с Hibernate или что-то может быть решена, тип, возвращаемый запросом неизвестно во время компиляции.поэтому, когда вы пишите
final List<MyObject> list = query.list();вы делаете небезопасный бросок из
ListдоList<MyObject>- этого нельзя избежать.нет таким образом, вы можете безопасно выполнять бросок как
Listможет ничего не содержат.единственный способ сделать ошибку уйти-это еще более уродливый
final List<MyObject> list = new LinkedList<>(); for(final Object o : query.list()) { list.add((MyObject)o); }
разрешение заключается в использовании TypedQuery вместо этого. При создании запроса из EntityManager вместо этого вызовите его следующим образом:
TypedQuery<[YourClass]> query = entityManager.createQuery("[your sql]", [YourClass].class); List<[YourClass]> list = query.getResultList(); //no type warningЭто также работает одинаково для именованных запросов, собственных именованных запросов и т. д. Соответствующие методы имеют те же имена, что и те, которые возвращают запрос vanilla. Просто используйте это вместо запроса, когда вы знаете тип возвращаемого значения.
вы можете избежать предупреждения компилятора с обходными путями, как этот:
List<?> resultRaw = query.list(); List<MyObj> result = new ArrayList<MyObj>(resultRaw.size()); for (Object o : resultRaw) { result.add((MyObj) o); }но есть некоторые проблемы с этим кодом:
- создан лишний ArrayList
- ненужный цикл по всем элементам, возвращаемых из запроса
- больше кода.
и разница только косметическая, поэтому использовать такие обходные пути - на мой взгляд-бессмысленно.
вы должны жить с этими предупреждениями или подавить их.
чтобы ответить на ваш вопрос, нет никакого "правильного пути", чтобы сделать это. Теперь, если это просто предупреждение, которое беспокоит вас, лучший способ избежать его распространения-обернуть
Query.list()метод в DAO:public class MyDAO { @SuppressWarnings("unchecked") public static <T> List<T> list(Query q){ return q.list(); } }таким образом вы можете использовать
@SuppressWarnings("unchecked")только один раз.
List<Person> list = new ArrayList<Person>(); Criteria criteria = this.getSessionFactory().getCurrentSession().createCriteria(Person.class); for (final Object o : criteria.list()) { list.add((Person) o); }
вы используете ResultTransformer вот так:
public List<Foo> activeObjects() { Session s = acquireSession(); Query q = s.createQuery("from foo where active"); q.setResultTransformer(Transformers.aliasToBean(Foo.class)); return (List<Foo>) q.list(); }
единственный способ, который работает для меня был с итератором.
Iterator iterator= query.list().iterator(); Destination dest; ArrayList<Destination> 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); }С другими методами, которые я нашел, у меня были проблемы с приведением
правильный способ-использовать трансформаторы Hibernate:
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);итерация througth Object [] является избыточной и будет иметь некоторое снижение производительности. Подробную информацию об использовании transofrmers вы найдете здесь: трансформаторы для HQL и SQL
Если вы ищете еще более простое решение, вы можете использовать out-of-the-box-map-transformer:
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");
Я нашел лучшее решение здесь, ключ этого вопроса является addEntity метод
public static void testSimpleSQL() { final Session session = sessionFactory.openSession(); SQLQuery q = session.createSQLQuery("select * from ENTITY"); q.addEntity(Entity.class); List<Entity> entities = q.list(); for (Entity entity : entities) { System.out.println(entity); } }
Comments