it-roy-ru.com

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.

73
perp

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

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

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

Если вы используете 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;
}

С этим решением однонаправленных отношений от ребенка к родителю достаточно, чтобы автоматически удалить всех детей. Это решение не требует никаких слушателей и т.д. Также запрос типа DELETE FROM Parent WHERE id = 1 удалит дочерние элементы.

66
Thomas Hunziker

Создайте двунаправленные отношения, например:

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
    private Set<Child> children;
}
14
tekumara

Я видел в однонаправленном @ManytoOne, удаление не работает, как ожидалось . Когда родитель удаляется, в идеале также следует удалить child, но удаляется только parent, а child не удаляется и остается как Orphan

Используются следующие технологии: Spring Boot/Spring Data JPA/Hibernate

Sprint Boot: 2.1.2. ВЫПУСК

Spring Data JPA/Hibernate используется для удаления строки .eg

parentRepository.delete(parent)

ParentRepository расширяет стандартный CRUD-репозиторий, как показано ниже ParentRepository extends CrudRepository<T, ID>

Следующее - мой класс сущности

@Entity(name = “child”)
public class Child  {

    @Id
    @GeneratedValue
    private long id;

    @ManyToOne( fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = “parent_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;
}

@Entity(name = “parent”)
public class Parent {

    @Id
    @GeneratedValue
    private long id;

    @Column(nullable = false, length = 50)
    private String firstName;


}
0
ranjesh