Обновить связанную сущность из обратного вызова прослушивателя событийJAVA

Программисты JAVA общаются здесь
Anonymous
Обновить связанную сущность из обратного вызова прослушивателя событий

Сообщение Anonymous »

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

Для простоты мы также сохраняем измененное свойство (значение) в дочернем объекте.

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

Getter/Setter ToString... опущены для простоты.

@Entity общественный класс ParentEntity { @Идентификатор @GeneratedValue частный идентификатор UUID; частное имя строки; частное строковое значение; @OneToMany(mappedBy = "родительский", cascade = CascadeType.ALL) частный List дети; } @Сущность общественный класс ChildEntity { @Идентификатор @GeneratedValue частный идентификатор UUID; @ManyToOne @JoinColumn(name="parent_id") частный родитель ParentEntity; частное строковое значение; } Используемый подход — прослушиватель событий Поскольку изменения вносятся с помощью разных сервисов и методов, мы ищем централизованное решение, поэтому мы решили использовать Event-Listeners в родителе, который запускает процесс обновления во всех его дочерних элементах.

Показаны только дополнительные методы

публичный класс ParentEntity { @PrePersist @PreUpdate недействительный onUpdate() { если (дети != ноль) { this.children.forEach(ChildEntity::update) } } } общественный класс ChildEntity { недействительное обновление () { если (родительский != ноль) { this.value = родительское.getValue(); } } } Проблема Этот подход не всегда обновляет дочерний объект при изменении значения родительского объекта.

Мы выявили множество факторов, влияющих на результат
[*]Аннотация @OneToMany для ParentEntity#children с нетерпеливым/ленивым извлечением [*]Аннотация @Fetch для ParentEntity#children, специфичная для Hibernate, с JOIN/SELECT/SUBSELECT [*]Доступ к дочернему списку в рамках той же транзакции, что и обновление. [*]Специально для весны: используйте findById репозитория или собственный findByName
Мы также пробовали использовать аннотации @EntityGraph, но отказались от этого подхода. поскольку это будет зависеть от доступа, что сводит на нет подход «одного метода».

вызов метода сохранения хранилища внутри транзакции не имеет никакого эффекта.

Это приводит к следующей матрице успеха/неуспеха

Результаты успешные: + неудачные: -

Дочерний список, помеченный режимом @OneToMan fetch LAZY и @Fetch
без аннотаций ПРИСОЕДИНИТЬ ВЫБРАТЬ или ПОДВЫБОР найти по идентификатору - + - найти по идентификатору и доступу + + + без аннотаций ПРИСОЕДИНИТЬ ВЫБРАТЬ или ПОДВЫБОР найти по имени - + - найти по имени и доступу + + +
Дочерний список, аннотированный с помощью @OneToMan fetch EAGER и режима @Fetch
без аннотаций ПРИСОЕДИНИТЬ ВЫБРАТЬ или ПОДВЫБОР найти по идентификатору - - - найти по идентификатору и доступу - - + без аннотаций ПРИСОЕДИНИТЬ ВЫБРАТЬ или ПОДВЫБОР найти по имени + + - найти по имени и доступу + + +
Небольшое примечание: я не мог опубликовать поиск по идентификатору и поиск по имени как одну таблицу — stackoverflow не позволил бы это сделать
Открытые вопросы [*]Почему вызовы репозитория по findById и findByName дают разные результаты? [*]Какую комбинацию аннотаций использовать? [*]Есть ли совершенно другой подход?
Исходный код и некоторые SpringBootTests с дополнительным выводом журнала можно найти на GitHub

Вернуться в «JAVA»