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 68

4 ответа:

отношения в JPA всегда однонаправленные, если вы не связываете родителя с дочерним в обоих направлениях. Каскадирование операций удаления от родителя к ребенку потребует отношения от родителя к ребенку (а не наоборот).

поэтому вам нужно сделать это:

  • либо измените однонаправленный @ManyToOne отношение к двунаправленному @ManyToOne, или однонаправленным @OneToMany. Затем вы можете каскадировать операции удаления так это EntityManager.remove удалить родителя и детей. Вы также можете указать orphanRemoval как true, чтобы удалить всех осиротевших детей, когда дочерняя сущность в родительской коллекции имеет значение null, т. е. удалить ребенка, когда он не присутствует в родительской коллекции.
  • или укажите ограничение внешнего ключа в дочерней таблице как ON DELETE CASCADE. Вам нужно будет вызвать EntityManager.clear() после вызова EntityManager.remove(parent) как настойчивость контекст должен быть обновлен - дочерние сущности не должны существовать в контексте сохраняемости после их удаления в базе данных.

Если вы используете hibernate в качестве поставщика JPA, вы можете использовать аннотацию @OnDelete. Эта аннотация добавит к отношению триггер ON DELETE CASCADE, который делегирует удаление дочерних элементов в базу данных.

пример:

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