Подтвердить что ты не робот

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

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

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

Предполагая модель с классом Order, которая имеет в ней набор OrderLines.

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

@OneToMany (выборка = FetchType.EAGER)?

Смотрите:

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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();

Ответ 5

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

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

Ответ 6

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

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

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

Крис

Ответ 7

Если проблема - это просто 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>