У вас есть вопрос, почему операция Cascade
не работает, когда вы добавляете Child
к Parent
и имеете каскадную аннотацию на Parent
.
Обычно владелец отношения, в данном случае Child
, как указано в аннотации mappedBy="parent"
, отвечает за сохранение отношения.Вы продемонстрировали это с помощью однонаправленного сопоставления для Child
- с аннотацией ManyToOne
.
Child child = new Child();
Parent parent = new Parent();
child.setParent(parent);
parentRepo.save(parent);
childRepo.save(child);
Затем вы попробовали то же самое с двунаправленным сопоставлением в Parent
-сделано с аннотацией OneToMany
.Поскольку эта аннотация включает аннотацию mappedBy="parent"
, она не является владельцем, и обычно все, что добавляется к Set<Child> children
, игнорируется.Однако вы добавили аннотацию cascade = CascadeType.ALL
, чтобы она переопределяла настройки владения и позволяла сущности Parent
сохранять отношения для подмножества операций и конкретных условий, определяемых значением CascadeType
.
Но какродитель, чтобы знать, какие дети сохранятся?Я предполагаю, что он проверяет, сохранился ли дочерний экземпляр.Если это так, то каскадная операция не потребуется.Когда вы сохранили дочерний экземпляр самостоятельно, вы обошли каскадную операцию.
Child child = new Child();
Parent parent = new Parent();
Set<Child> children = new HashSet<>();
childRepo.save(child);
children.add(child);
parent.setChildren(children);
parentRepo.save(parent);
Этот конкретный код выдает мне ошибку, поскольку дочерний экземпляр был сохранен и отключен, а затем попросил сохранить его снова.Условие ошибки не всегда возникает - я думаю, в зависимости от того, является ли родительский объект новым или был получен из базы данных.
org.hibernate.PersistentObjectException: отдельная сущность передана для сохранения:
Поэтому, если вы хотите, чтобы объект Parent
делал каскад, вы должны передать ему экземпляр Child
, который еще не был сохранен.Обратите внимание, что вам все равно нужно установить родителя дочернего элемента, чтобы создать отношение, иначе родительский объект останется бездетным дочерним элементом.
Child child = new Child();
Parent parent = new Parent();
child.setParent(parent);
Set<Child> children = new HashSet<>();
children.add(child);
parent.setChildren(children);
parentRepo.saveAndFlush(parent);
И это прекрасно работает для меня.Обратите внимание, что я сам создаю Set
детей вместо того, чтобы создавать его каждый раз, когда создается экземпляр Parent
.Как правило, вы будете выполнять запросы к базе данных гораздо чаще, чем обновления, и для каждого запроса провайдер JPA будет помещать свой собственный класс Collection
в свойство children
Parent
, и поэтому набор, который вы создали, обычно заканчиваетсяна куче мусора - несколько неэффективно.
@Entity
public class Child {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
@Entity
public class Parent {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval=true)
private Set<Child> children;