Hibernate N + 1 SELECT с объектами DTO - PullRequest
1 голос
/ 28 февраля 2012

У меня проблема с hibernate, когда он выполняет N + 1 SELECTS при использовании объекта DTO.

Например, этот запрос JPQL:

SELECT com.acme.MyDto(t) FROM Thing t

Где конструктор MyDtoэто что-то вроде:

public MyDto(Thing t) {
   ...
}

Что приводит к запросу чего-то вроде:

SELECT t.id FROM thing t WHERE condition

, за которым следуют все отдельные запросы для каждой строки, то есть:

SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 1
SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 2
SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 3
...

Однако, если конструктор не принимает Entity, а вместо этого каждый отдельный столбец, то hibernate ведет себя так, как вы ожидаете, то есть:

public MyDto(Integer id, String column1, String column2) {
   ...
}

Тогда сгенерированный SQL выглядит так:

SELECT t.id, t.column1, t.column2 FROM thing t WHERE condition

Помимо создания конструкторов DTO, которые занимают каждый столбец, есть ли способ коаксиального спящего режима, чтобы просто выбрать все столбцы сразу с начала?

Таблица, с которой мы работаем, имеет 100+ столбцы разбросаны по встраиваемым объектам, поэтому довольно сложно поддерживать огромный конструктор.Таблица чрезвычайно нормализована и не имеет соединений.

Ответы [ 2 ]

1 голос
/ 28 февраля 2012

В первый раз прочитайте ваш вопрос неправильно ... Я не помню, чтобы использовались DTO, если они просто берут всю сущность, а не только некоторые конкретные столбцы, поэтому я не уверен, почему Hibernate ведет себя так, когда вы используете целоесущность как параметр в конструкторе DTO.В любом случае, вы можете обойти это, просто получая фактический Things с помощью запроса, а затем построить DTO в цикле, что-то вроде:

public List<ThingDTO> getThingDTOs( ... )
{
    Query query = em().createQuery("FROM Thing t WHERE ...");
    query.setParameter( ... );

    List<Thing> things = query.getResultList();

    List<ThingDTO> thingDTOs = new ArrayList(things.size());
    for(Thing t : things)
    {
        thingDTOs.add(new ThingDTO(t));
    }

    return thingDTOs
}

Это не красиво, но этоспособ, которым Hibernate должен извлечь все необходимые строки за один раз

0 голосов
/ 19 июля 2018

Как вы, наверное, уже заметили, подход с использованием выражений конструктора имеет некоторые недостатки. Если вам нужны вложенные ассоциации, будет еще хуже. Основная проблема при работе с объектными объектами заключается в том, что вы все равно можете столкнуться с проблемами N + 1 запросов. Я написал сообщение в блоге на эту тему некоторое время назад, в котором объясняется, почему я создал Blaze-Persistence Entity Views , библиотеку, которая позволяет отображать DTO как интерфейсы.

...