Динамическая нетерпеливая и ленивая загрузка в спящем режиме

Я новичок в Hibernate, но у меня большой опыт работы с Entity Framework на C#. Одна функция, которая мне нравится, — это возможность динамически решать, что сразу загружать в запросе. Например, рассмотрим отношение «один ко многим» сущностей класса и учащегося.

На странице "Просмотр классов" я могу сделать это:

context.Configuration.EnableLazyLoading = true; //default option
List<Classes> classes = context.Classes.ToList();

Теперь я могу просто показать информацию о классе, не тратя ресурсы на сбор данных об учениках. ТОЛЬКО когда пользователь нажимает «Просмотреть классы со списками», я делаю следующее:

context.Configuration.EnableLazyLoading = true;
List<Classes> classes = context.Classes.Include(c => c.Students).ToList();

С помощью одного этого утверждения я смог решить, что в этой конкретной ситуации я хочу получить всю информацию сразу. Не два запроса. Не сто запросов. Всего один запрос. Все, несмотря на загрузку только классов за несколько секунд до этого.

Все, что я читал о Hibernate, объясняет, как вы можете указать lazy="true|false" в файлах конфигурации отношений, но я действительно хочу иметь возможность решать, когда загружать коллекции на лету. В конце концов, я не заинтересован в покупке машины, которая едет только со скоростью 30 или 60 миль в час. Мне нужно выбрать скорость в зависимости от того, где я нахожусь.

Возможно, вариант использования режима выборки в качестве JOIN приемлем в том смысле, что в данной ситуации будет всего два запроса (один для класса и один для учеников), но мне очень понравилась возможность сделать все это в одном запросе, особенно если у меня есть несколько дочерних коллекций для загрузки и я не хочу выполнять запрос для каждой связи. Я понимаю, что соединения «все сразу» создают дополнительные данные, которые необходимо передавать в потоковом режиме, но я удивлен, что этот уровень контроля не так просто реализовать или он может быть полностью недоступен.


person AirmanAJK    schedule 26.01.2016    source источник
comment
Какой у Вас вопрос?   -  person Tim Biegeleisen    schedule 26.01.2016


Ответы (2)


Hibernate не имеет очень удобных способов динамической выборки. Вы можете контролировать его с помощью

  1. Использование динамической выборки с помощью запросов HQL с join fetch (как предложил @ThibaultClement).
  2. Использование динамической выборки ассоциаций с Criteria.setFetchMode().
  3. Использование динамического получения через профили с пометкой @FetchProfile.

Вы также можете сослаться на объединенный запрос HQL, чтобы получить большое количество отношений для дополнительных мыслей.

person v.ladynev    schedule 26.01.2016
comment
Справедливо. Я хотел убедиться, что не упускаю из виду что-то очевидное, тем более, что в Hibernate есть разные способы сбора данных. Мне просто нужно выйти из мышления Entity Framework и понять, что разные ORM не будут иметь соответствия функций 1-1. - person AirmanAJK; 26.01.2016
comment
@AirmanAJK Возможно, вам будет интересно взглянуть на Querydsl, если вы этого не сделаете. сделать это еще. - person v.ladynev; 26.01.2016

Как упомянул @v.ladynev, querydsl — хороший вариант. Тем не менее, на мой взгляд, нет чистого способа справиться с этим.

  1. Если вы используете .select(...) результатом будет Tuple, а не исходный объект (с неупомянутыми полями, по умолчанию равными null), что приведет к написанию некоторого стандартного кода для сопоставления его с исходным объектом.
  2. Другим возможным решением, связанным с querydsl, является использование QueryProjection, но оно опять же требует от вас написания отдельного класса с другими возможностями.
  3. Третье решение может заключаться в том, чтобы сохранить все соединения как Fetch.LAZY, а затем использовать JpaUtils.initialize() (или собственный метод hibernate) для получения графа объектов по мере необходимости. (Но что касается производительности, это будет хуже, чем использование join fetch напрямую, которое сделает только 1 вызов sql).
  4. Другой вариант третьего варианта, на который стоит обратить внимание, — это использование NamedEntityGraph или EntityGraph для выборки необходимых частей.
person Gulats    schedule 03.08.2018