Почему операция слияния JPA вызывает множественный выбор перед обновлением? - PullRequest
0 голосов
/ 12 сентября 2018

Мы используем репозитории Spring Data с Hibernate 5.x

У нас есть граф сущностей с глубокой иерархией. Отображение выглядит так:

@Entity
public class FooBar {
    @OneToMany(mappedBy = "fooBar", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Foo> chassis = new HashSet<>(0);

    ...
}

@Entity
public class Foo {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "foobar_id")
    private FooBar fooBar;

    @OneToMany(mappedBy = "foo", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Bar> chassis = new HashSet<>(0);

    ...
}

@Entity
public class Bar {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "foo_id")
    private FooBar foo;

    ...
}

Как видите, у сущности FooBar есть набор сущностей Foo. Каждая сущность Foo содержит больше сущностей Bar и т. Д.

Мы используем функцию Fetchgraph, чтобы загрузить сущность FooBar с отношениями, которые нам нужны во время выполнения, чтобы избежать проблемы n + 1 запроса при выборке ленивых ассоциаций. После вызова службы для загрузки графа сущности транзакция закончилась, и сущность отсоединилась.

При последующем вызове save для объекта FooBar это вызывает несколько операторов выбора. Каждый выбирает одну из дочерних сущностей.

Я знаю, что это происходит из вызова entitymanager merge (), который выбирает граф объектов из БД перед копированием изменений состояния из отсоединенных объектов.

У меня два вопроса:

  1. Почему hibernate не может объединить эти операторы в один большой выбор, например, что происходит при использовании fetchgraph?

  2. Когда я удаляю все каскадные опции из отношений, он все равно вызывает множественный выбор, но будут обновляться только атрибуты вершины, сущности FooBar. Почему hibernate по-прежнему извлекает все загруженные дочерние объекты во время объединения даже без каскадного объединения?

Спасибо

1 Ответ

0 голосов
/ 12 сентября 2018

Как объяснено в этой статье , вы можете использовать session.update вместо слияния для преодоления этой проблемы.

Session session = entityManager.unwrap( Session.class );

for ( Post post: posts ) {
    session.update( post );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...