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;
    }