Каков "правильный"способ выполнения запроса 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 сайт, так что я немного насторожен.



код, после компиляции работает без видимого... это мне известно... тем не менее, и результаты являются ожидаемыми.



Итак: я делаю это право? Я упускаю что-то очевидное? Есть "официальный"
или "рекомендуется"Способ Сделать Это?

546   9  

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

    Ничего не найдено.