Hibernate (JPA), как выполнить быстрый запрос, загрузив все дочерние объекты

StackOverflow https://stackoverflow.com/questions/70992

  •  09-06-2019
  •  | 
  •  

Вопрос

Что касается моего предыдущий вопрос, я хочу убедиться, что все дочерние объекты загружены, поскольку у меня есть несколько потоков, которым может потребоваться доступ к данным (и, таким образом, избежать исключений отложенной загрузки).Я понимаю, что это можно сделать с помощью ключевого слова "fetch" в запросе (EJB QL).Так:

select distinct o from Order o left join fetch o.orderLines

Если предположить, что модель с Order класс, который имеет набор OrderLines в этом.

Мой вопрос в том, что ключевое слово "distinct", похоже, необходимо, иначе я, похоже, получу обратно Order для каждого OrderLine.Правильно ли я поступаю?

Возможно, что еще более важно, есть ли способ извлечь все дочерние объекты, независимо от их глубины?У нас около 10-15 классов и для сервера нам понадобится все загруженное...Я избегал использования FetchType.EAGER поскольку это означало, что он всегда готов, и, в частности, веб-интерфейс загружает все - но, возможно, это правильный путь - это то, что вы делаете?Кажется, я помню, как мы пробовали это раньше, а затем получили очень медленные веб-страницы - но, возможно, это означает, что нам следует использовать кеш второго уровня?

Это было полезно?

Решение

Изменение аннотации - плохая идея, ИМХО.Поскольку его нельзя изменить на ленивый во время выполнения.Лучше сделать все ленивым и получать по мере необходимости.

Я не уверен, что понимаю вашу проблему без сопоставлений.Выборка левого соединения должна быть всем, что вам нужно для описанного вами варианта использования.Конечно, вы получите заказ для каждой строки заказа, если строка заказа имеет заказ в качестве родителя.

Другие советы

Я не уверен насчет использования ключевого слова fetch в вашем EJBQL, возможно, вы путаете его с аннотацией...

Пробовали ли вы добавить свойство FetchType в атрибут отношений?

@OneToMany(fetch=FetchType.EAGER)?

Видеть:

http://java.sun.com/javaee/5/docs/api/javax/persistence/FetchType.html http://www.jroller.com/eyallupu/entry/hibernate_Exception_simultiously_fetch_multiple

Вы пробовали использовать преобразователь результатов?Если вы используете запросы Criteria, вы можете применить преобразователь результатов (хотя есть некоторые проблемы с нумерацией страниц и преобразователем результатов):

Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.list();

тот em.getDelegate() это хак, который работает только в том случае, если вы используете спящий режим.

Возможно, что еще более важно, есть ли способ привлечь все детские объекты, независимо от того, насколько глубоко?У нас около 10-15 классов, и для сервера нам понадобится все загруженное ...Я избегал использования fetchtype.eager, так как это означало, что он всегда стремится, и, в частности, передняя часть веб -фронта загружает все - но, возможно, это путь - это то, что вы делаете?Кажется, я помню, как мы пробовали это раньше, а затем получали очень медленные веб -страницы - но, возможно, это означает, что мы должны использовать кэш второго уровня?

Если вам все еще интересно, я ответил на аналогичный вопрос в этой теме. как сериализовать коллекции спящего режима.

По сути, вы используете утилиту под названием бульдозер который сопоставляет bean-компоненты с другими bean-компонентами, и тем самым вы запускаете все свои ленивые загрузки.Как вы понимаете, это работает лучше, если все коллекции извлекаются быстро.

Возможно, вы сможете сделать что-то подобное, используя (отдельный) запрос критериев и установив режим выборки.Например.,

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession();
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id));
dc.setFetchMode("innerTable", FetchMode.JOIN);
Criteria c = dc.getExecutableCriteria(s);
MyEntity a = (MyEntity)c.uniqueResult();

Это будет работать только для отношений ManyToOne, и для них, вероятно, подойдет @ManyToOne(fetch=FetchType.EAGER).

Извлечение более одного отношения OneToMany не рекомендуется и/или не работает, как вы можете прочитать в ссылке, опубликованной Джереми.Просто подумайте об операторе SQL, который понадобится для такой выборки...

Что я сделал, так это реорганизовал код, чтобы сохранить карту объектов для менеджеров сущностей, и каждый раз, когда мне нужно обновить, закрываю старый менеджер сущностей для объекта и открываю новый.Я использовал приведенный выше запрос без принести так как это слишком глубоко для моих нужд - простое соединение втягивает OrderLines - принести заставляет идти еще глубже.

Есть только несколько объектов, для которых мне это нужно, около 20, поэтому я думаю, что накладные расходы на ресурсы при наличии 20 открытых менеджеров сущностей не являются проблемой - хотя администраторы баз данных могут иметь другое мнение, когда это выйдет в свет...

Я также переработал все так, чтобы работа с БД выполнялась в основном потоке и имела менеджер сущностей.

Крис

Если проблема заключается только в LazyInitializationExceptions, вы можете избежать этого, добавив OpenSessionInViewFilter.
Это позволит загружать объекты в представление, но не решит проблему скорости.

     <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top