JPA: однонаправленное много-к-одному и каскадное удаление
скажем, у меня есть однонаправленный @ManyToOne
отношения следующим образом:
@Entity
public class Parent implements Serializable {
@Id
@GeneratedValue
private long id;
}
@Entity
public class Child implements Serializable {
@Id
@GeneratedValue
private long id;
@ManyToOne
@JoinColumn
private Parent parent;
}
если у меня есть родитель P и дети c1...Cn ссылаясь на P, есть ли чистый и красивый способ в JPA автоматически удалять детей c1...Cn когда P удаляется (т. е. entityManager.remove(P)
)?
то, что я ищу-это функциональность, аналогичную ON DELETE CASCADE
в SQL.
4 ответов
отношения в JPA всегда однонаправленные, если вы не связываете родителя с ребенком в обоих направлениях. Каскадные операции удаления от родителя к ребенку потребуют отношения от родителя к ребенку (а не наоборот).
поэтому вам нужно будет сделать это:
- либо измените однонаправленный
@ManyToOne
отношение к двунаправленному@ManyToOne
, или однонаправленным@OneToMany
. Тогда можно снять каскад операций этоEntityManager.remove
удалить родителя и детей. Вы также можете указатьorphanRemoval
как true, чтобы удалить любые осиротевшие дочерние элементы, когда дочерняя сущность в родительской коллекции имеет значение null, т. е. удалить дочерний элемент, когда он отсутствует в родительской коллекции. - или укажите ограничение внешнего ключа в дочерней таблице как
ON DELETE CASCADE
. Вам нужно будет вызватьEntityManager.clear()
после вызоваEntityManager.remove(parent)
как настойчивость контекст должен быть обновлен - дочерние сущности не должны существовать в контексте сохранения после их удаления в базе данных.
Если вы используете hibernate в качестве поставщика JPA, вы можете использовать аннотацию @OnDelete. Эта аннотация добавит к отношению триггер НА УДАЛИТЬ КАСКАД, который делегирует удаление дочерних элементов в базу данных.
пример:
public class Parent {
@Id
private long id;
}
public class Child {
@Id
private long id;
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
}
С помощью этого решения однонаправленной связи от ребенка к родителю достаточно, чтобы автоматически удалить всех детей. Это решение не нуждается в слушателях и т. д. Также запрос удалить из родительского, где id = 1 удалить детей.
создайте двунаправленное отношение, например:
@Entity
public class Parent implements Serializable {
@Id
@GeneratedValue
private long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
private Set<Child> children;
}
@ Cascade (org.зимовать.комментарии.CascadeType.DELETE_ORPHAN)
данная аннотация работала для меня. Можно попробовать
Например:
public class Parent{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="cct_id")
private Integer cct_id;
@OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true)
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private List<Child> childs;
}
public class Child{
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="cct_id")
private Parent parent;
}