Вопрос

У меня проблема с простым @OneToMany сопоставление между родительским и дочерним объектом.Все работает хорошо, только дочерние записи не удаляются, когда я удаляю их из коллекции.

Родитель:

@Entity
public class Parent {
    @Id
    @Column(name = "ID")
    private Long id;

    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "parent")
    private Set<Child> childs = new HashSet<Child>();

 ...
}

Ребенок:

@Entity
public class Child {
    @Id
    @Column(name = "ID")
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="PARENTID", nullable = false)
    private Parent parent;

  ...
}

Если я теперь удалю дочерний элемент из набора дочерних элементов, он не будет удален из базы данных.Я попробовал обнулить child.parent ссылку, но это тоже не сработало.

Сущности используются в веб-приложении, удаление происходит как часть запроса Ajax.У меня нет списка удаленных дочерних элементов при нажатии кнопки сохранения, поэтому я не могу удалить их неявно.

Это было полезно?

Решение

Поведение JPA правильное (то есть согласно спецификации):объекты не удаляются просто потому, что вы удалили их из коллекции OneToMany.Существуют расширения, специфичные для конкретного поставщика, которые делают это, но собственный JPA этого не поддерживает.

Частично это связано с тем, что JPA на самом деле не знает, следует ли удалять что-то удаленное из коллекции.С точки зрения объектного моделирования, в этом заключается разница между состав и «агрегация*.

В состав, дочерняя сущность не существует без родителя.Классический пример – между Домом и Комнатой.Удалите Дом и Комнаты тоже.

Агрегация — это более свободный вид ассоциации, типичный пример которого — «Курс» и «Студент».Удалите курс, и студент все еще существует (возможно, в других курсах).

Поэтому вам нужно либо использовать расширения, специфичные для поставщика, чтобы принудительно выполнить такое поведение (если доступно), либо явно удалить дочерний элемент И удалить его из родительской коллекции.

Я знаю:

Другие советы

В дополнение к ответу Клетуса, JPA 2.0, окончательный с декабря 2010 года, вводит orphanRemoval атрибут включен @OneToMany аннотации.Более подробную информацию см. здесь запись в блоге.

Обратите внимание: поскольку спецификация относительно новая, не все поставщики JPA 1 имеют окончательную реализацию JPA 2.Например, Выпуск Hibernate 3.5.0-Beta-2 еще не поддерживает этот атрибут.

Вы можете попробовать это:

@OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true).

Как уже объяснялось, с JPA невозможно делать то, что я хочу, поэтому я использовал аннотацию hibernate.cascade, благодаря чему соответствующий код в родительском классе теперь выглядит следующим образом:

@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, mappedBy = "parent")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,
            org.hibernate.annotations.CascadeType.DELETE,
            org.hibernate.annotations.CascadeType.MERGE,
            org.hibernate.annotations.CascadeType.PERSIST,
            org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
private Set<Child> childs = new HashSet<Child>();

Я не мог просто использовать «ВСЕ», так как это также удалило бы родителя.

Здесь каскад в контексте удаления означает, что дочерние элементы удаляются, если вы удаляете родителя.Не ассоциация.Если вы используете Hibernate в качестве поставщика JPA, вы можете сделать это, используя конкретный каскад спящего режима.

Вы можете попробовать это:

@OneToOne(cascade = CascadeType.REFRESH) 

или

@OneToMany(cascade = CascadeType.REFRESH)
@Entity 
class Employee {
     @OneToOne(orphanRemoval=true)
     private Address address;
}

Видеть здесь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top