JPA2 / Hibernate - Хватит ленивой загрузки? - PullRequest
9 голосов
/ 26 января 2011

У меня проблема с тем, что JPA пытается лениво загрузить мои данные, когда я этого не хочу. По сути дела, я использую Сервис для извлечения некоторых данных, и когда я собираюсь проанализировать эти данные в JSON, библиотека JSON запускает режим гибернации, чтобы попытаться лениво загрузить данные. Есть ли способ остановить это? Я привел пример ниже.

// Web Controller method
public String getEmployeesByQuery(String query) {

    Gson gson = new Gson();
    List<Employee> employees = employeeService.findEmployeesByQuery(query);

    // Here is where the problem is occurring - the gson.toJSON() method is (I imagine)
    // using my getters to format the JSON output, which is triggering hibernate to
    // try and lazily load my data...
    return gson.toJSON(employees);
}

Можно ли установить JPA / hibernate, чтобы не пытаться лениво загружать данные?

ОБНОВЛЕНИЕ: Я понимаю, что вы можете использовать FetchType.EAGER - но что, если я не хочу загружать эти данные? Я просто хочу остановить спящий режим от попыток получить больше данных - у меня уже есть данные, которые я хочу. Прямо сейчас всякий раз, когда я пытаюсь получить доступ к методу get (), hibernate выдает ошибку «нет сеанса или сеанс закрыт», что имеет смысл, поскольку моя транзакция уже была зафиксирована из моего сервиса.

Спасибо!

Ответы [ 8 ]

6 голосов
/ 26 января 2011

Существует несколько вариантов:

  • Если вам всегда нужно загружать свою коллекцию с нетерпением, вы можете указать fetch = FetchType.EAGER в своем отображении, как предлагается в других ответах.

  • В противном случае вы можете включить активную выборку для конкретного запроса:

    • Используя выражение JOIN FETCH в запросе HQL / JPQL:

      SELECT e FROM Employee e JOIN FETCH e.children WHERE ...
      
    • Используя выборку профилей (в JPA вы можете получить доступ к Hibernate Session через em.unwrap(Session.class))
3 голосов
/ 26 января 2011

У вас действительно есть два варианта:

  1. Вы можете скопировать данные с сотрудника на тот, который не передается через Hibernate.
  2. Посмотрите, есть ли способ, чтобы библиотека toJSON не отражала весь граф объекта. Я знаю, что некоторые библиотеки JSON позволяют сериализовать только некоторые свойства объекта в JSON.

Лично я бы подумал, что # 1 было бы проще, если бы ваша библиотека использовала только отражение.

2 голосов
/ 26 января 2011

Как уже говорили другие, это не проблема JPA / hibernate, а скорее используемая библиотека сериализации json.Вы должны дать команду gson, чтобы исключить свойства, которые вы не хотите просматривать.

1 голос
/ 26 января 2011

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

Вы можете использовать Doozer , чтобы сделать это. Он очень гибок, и благодаря небольшой конфигурации (читай вы потеряете свои волосы, настраивая его ), вы можете даже частично получить данные, которые хотите отправить в Gson.

0 голосов
/ 27 июля 2011

Простая и понятная задача - создать новые классы данных (что-то вроде DTO). используйте Hibernate.isInitialized (), чтобы проверить, инициализирован ли объект hibernate или нет. Я проверяю GSON, если я могу переопределить что-нибудь. Я опубликую это здесь, если найду что-то новое.

0 голосов
/ 26 января 2011

Ваша проблема в том, что вы сериализуете данные. Мы столкнулись с такой же проблемой с Flex и JPA / Hibernate. Хитрость в том, в зависимости от того, насколько вы хотите манипулировать вещами, либо

  1. Измените модель данных, чтобы не преследовать данные, которые вам не нужны.
  2. Скопируйте нужные вам данные в какой-то DTO, у которого нет никаких отношений, о которых нужно беспокоиться.
  3. Предполагая, что вы используете Hibernate, добавьте фильтр Session-in-view .... он примерно такой, он будет держать сеанс открытым, пока вы сериализуете всю базу данных. ;)

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

YMMV

0 голосов
/ 26 января 2011

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

0 голосов
/ 26 января 2011

Да:

@*ToMany(fetch=FetchType.EAGER)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...