Это на самом деле задумано.Причина вызова 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
ассоциацию, чтобы дочерняя сторонаАссоциации управляет этим.