JPA @PreUpdate вызывается для всех дочерних объектов при добавлении нового дочернего объекта в родительский. - PullRequest
0 голосов
/ 06 июня 2018

У меня отношения один-ко-многим между родителем и ребенком.Ниже приведен фрагмент кода отношения.

@Entity
@Table(name = "Parent")
public class Parent{

    @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    @JoinColumn(name = "parentId",referencedColumnName="parentId")
    private Set<Child> child = new HashSet<>();
}

Кроме того, я использую @PreUpdate и @PrePersist для выполнения какой-либо операции аудита на объекте, прежде чем пытаться сохранить и обновить объекты.

@PrePresist выглядит нормально.Он вызывается до того, как я пытаюсь сохранить новый объект в хранилище данных, как указано в документации.

У меня возникают проблемы при использовании @PreUpdate.Если у родителя несколько детей, и когда мы пытаемся добавить к нему еще одного ребенка entityManager.merge(parent).@PrePresist вызывается правильно, когда мы вставляем новую дочернюю запись, но он также вызывает аннотированный метод @PreUpdate для всех дочерних элементов, которые уже присутствуют в родительском элементе, хотя в дочернем объекте ничего не изменилось.Он не должен был вызывать PreUpdate для всех детей, поскольку в них ничего не обновляется.

Кто-нибудь знает, почему это происходит?

Заранее спасибо!

1 Ответ

0 голосов
/ 06 июня 2018

Это на самом деле задумано.Причина вызова PreUpdate для всех дочерних элементов заключается в том, что в этом случае hibernate сначала удаляет всех дочерних элементов, а затем вставляет их заново.Это поведение описано в http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-many-unidirectional.

У вас есть эта проблема, потому что в этом случае родитель владеет ассоциацией.Это означает, что при сохранении родителя связь между родителем и потомками обновляется в базе данных.Нет другого способа сделать это, кроме как удалить все дочерние элементы и вставить их заново.

Можно было бы предложить решение, в котором Hibernate отслеживает, какие изменения были внесены в коллекцию, и просто вставляет записи, которые были добавлены, и удаляет записи, которые были удалены.Хотя это кажется решением, но оно не будет работать, если связь уже была изменена в базе данных.

Суть проблемы заключается в том, что когда клиент вызывает parent.save, он ожидает, что после завершения сохранения база данных будет содержатьзаписи для дочерних элементов, связанных с parent, которые были в коллекции children при вызове save.

Если hibernate просто отслеживает добавления и удаления и выполняет только эти операции, следующий сценарий вызовет проблему.

Предположим, что родительский объект уже связан с двумя дочерними элементами:

Parent parent = new Parent();
parent.children(asSet(child1, child2));
parent.save();

Затем два клиента одновременно читают родительское состояние из базы данных.

Клиент 1:

Parent parent = dao.getParent(parentId);

Клиент 2:

Parent parent = dao.getParent(parentId);

Первый клиент добавляет ребенка и сохраняет:

parent.children().add(child3);
parent.save();

Пока все хорошо.Но у второго клиента все еще есть версия родителя, которая имеет только child1 и child2.Если этот клиент, например, удаляет child1 и сохраняет:

parent.children().remove(child1);
parent.save();

Он ожидает, что родительский объект теперь содержит только child2 (как, например, children коллекция, содержащаяся в момент сохранения).Но если мы используем реализацию отслеживания, и такое удаление вызывает только что-то вроде:

DELETE FROM child where parent_id = <parent_id> and id = <child1_id>

, тогда все еще будут две записи, связанные с этим родителем - child2 и child3.

Надеюсь, что это имеет смысл и объясняет, почему hibernates удаляет всех дочерних элементов и вставляет их заново.

Для решения вашей проблемы вам нужно использовать двунаправленную OneToMany ассоциацию, чтобы дочерняя сторонаАссоциации управляет этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...