Получить несколько отношений onetoMany Hibernate JPA - PullRequest
7 голосов
/ 13 июля 2010

Я использую Hibernate JPA 1.0.

У меня есть следующий тип модели, и я считаю, что отношения manyToOne и oneToOne "с нетерпением" выбраны, а oneToMany "лениво" получены.

Я хочуполучить объект A и все его ассоциации, где a.id =?

  • A oneToMany B
    • B oneToOne C
      • C oneToMany D
    • B oneToOne E
      • E oneToMany D
    • B oneToOne F
      • F oneToMany D

Можно ли загрузить эту сущность в одном запросе?Или в подмножестве запросов, исключая проблему "n + 1 selects"!

До сих пор моим решением для загрузки всех ассоциаций A было следующее:

"Select DISTINCT aиз A JOIN FETCH a.bs WHERE a.id =: aID "

И затем выполнить итерацию с использованием кода для извлечения всех других ассоциаций.

Коллекция B bs = A.getBs ();

         for (final B b : bs) {
         b.getCs().getDs().size();
         b.getEs().getDs().size();
         b.getFs().getDs().size();
         }

Очевидно, что должен быть лучший способ сделать это.

Ответы [ 3 ]

6 голосов
/ 15 марта 2013

Возможно, вам будет интересно прочитать эту статью. Я проверил оба

@Fetch(FetchMode.SUBSELECT)

и также использует Set вместо List, в сочетании с fetch = FetchType.EAGER это работает.

2 голосов
/ 13 июля 2010

Используйте FETCH JOIN. Из спецификации JPA 1.0:

4.4.5.3 Выборка соединений

FETCH JOIN включает выбор ассоциации в качестве побочного эффекта исполнения запрос. FETCH JOIN указан более юридическое лицо и связанные с ним юридические лица.

Синтаксис для соединения извлечения:

fetch_join ::= [ LEFT [OUTER] | INNER ] JOIN FETCH join_association_path_expression

Ассоциация, на которую ссылается правая часть предложения FETCH JOIN должна быть ассоциация, которая принадлежит сущность, которая возвращается в результате запроса. Это не разрешено указать идентификационную переменную для лица, на которые ссылаются по праву сторона предложения FETCH JOIN, и отсюда ссылки на неявно извлеченные объекты не могут появиться в другом месте запроса.

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

SELECT d
FROM Department d LEFT JOIN FETCH d.employees
WHERE d.deptno = 1

Соединение извлечения имеет такое же соединение семантика как соответствующий внутренний или внешнее соединение, за исключением того, что связанный объекты, указанные справа сторона операции соединения не возвращается в результате запроса или иначе упоминается в запросе. Отсюда, например, если отдел 1 имеет пять сотрудников, вышеуказанный запрос возвращает пять ссылок на отдел 1 субъект.

Конечно, используйте это с умом, не объединяйте слишком много столов, иначе вы убьете выступления.

0 голосов
/ 17 мая 2018

Ищете ответ из достоверных и / или официальных источников.

Как насчет документации JBoss ORM?

https://docs.jboss.org/hibernate/orm/current/userguide/html_single/chapters/fetching/Fetching.html

Существует несколько областей определения выборки:

статическая

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

SELECT Выполняет отдельный выбор SQL для загрузки данных.Это может быть EAGER (второй выбор выдается немедленно) или LAZY (второй выбор откладывается до тех пор, пока не потребуются данные).Эта стратегия обычно называется N + 1.

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

BATCH Выполняет отдельный выбор SQL для загрузки ряда связанных элементов данных, используя ограничение IN как частьSQL-предложение WHERE, основанное на размере пакета.Опять же, это может быть EAGER (второй выбор выполняется немедленно) или LAZY (второй выбор задерживается до тех пор, пока не потребуются данные).

SUBSELECT Выполняет отдельный выбор SQL для загрузкисвязанные данные на основе ограничения SQL, используемого для загрузки владельца.Опять же, это может быть либо EAGER (второй выбор выдается немедленно), либо LAZY (второй выбор откладывается до тех пор, пока не потребуются данные).


динамический (иногда упоминается как время выполнения)

Динамическое определение действительно ориентировано на прецедент.Существует несколько способов определения динамической выборки:

Профили выборки , определенные в отображениях, но их можно включить / отключить в сеансе.

HQL / JPQL и запросы Hibernate и JPA Criteria имеют возможность указать выборку, специфичную для указанного запроса.

Графы сущностей Начиная с Hibernate 4.2 (JPA 2.1), это также вариант.

И чтобы доказать ответ выше, вот пример:

FetchMode.SUBSELECT Чтобы продемонстрировать, как работает FetchMode.SUBSELECT, мы собираемся изменитьпример отображения FetchMode.SELECT для использования FetchMode.SUBSELECT:

Пример 17. Пример отображения FetchMode.SUBSELECT:

@OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Employee> employees = new ArrayList<>();

Теперь мы собираемся получить всеСубъекты отдела, которые соответствуют заданным
критериям фильтрации и затем перемещаются по коллекциям своих сотрудников.

Hibernate избежит проблемы с запросом N + 1, создав один оператор SQL для инициализации всех ихКоллекции ployees для всех подразделений Департамента, которые были ранее получены.Вместо того чтобы передавать все идентификаторы сущностей, Hibernate просто перезапускает предыдущий запрос, который выбрал сущности Department.

Пример 18. Пример отображения FetchMode.SUBSELECT:

List<Department> departments = entityManager.createQuery(
    "select d " +
    "from Department d " +
    "where d.name like :token", Department.class)
    .setParameter( "token", "Department%" )
    .getResultList();

log.infof( "Fetched %d Departments", departments.size());

for (Department department : departments ) {
    assertEquals(3, department.getEmployees().size());
}

- Получил 2 отдела

SELECT
    d.id as id1_0_
FROM
    Department d
where
    d.name like 'Department%'

-- Fetched 2 Departments

SELECT
    e.department_id as departme3_1_1_,
    e.id as id1_1_1_,
    e.id as id1_1_0_,
    e.department_id as departme3_1_0_,
    e.username as username2_1_0_
FROM
    Employee e
WHERE
    e.department_id in (
        SELECT
            fetchmodes0_.id
        FROM
            Department fetchmodes0_
        WHERE
            d.name like 'Department%'
    )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...