JPA OneToMany не удаляет ребенка

у меня проблема с простым @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;

  ...
}

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

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

7 ответов


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

отчасти это потому, что JPA на самом деле не знает, следует ли удалять что-то удаленное из коллекции. В терминах объектного моделирования это разница между состав и "агрегация.*

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

агрегация является более свободным видом ассоциации и типизируется курсом и студентом. Удалите курс, и студент все еще существует (возможно, в других курсах).

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

Я в курсе:


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

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


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

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


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

@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>();

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


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


@Entity 
class Employee {
     @OneToOne(orphanRemoval=true)
     private Address address;
}

посмотреть здесь.


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

@OneToOne(cascade = CascadeType.REFRESH) 

или

@OneToMany(cascade = CascadeType.REFRESH)