簡體   English   中英

如何使用Hibernate級聯刪除孩子?

[英]How to cascade child deletion using Hibernate?

我目前有一個類似於以下內容的設置:

@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
    private Long id;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

@Entity
public class Container extends AbstractEntity {
    private Collection<Item> items = new HashSet<>();

    @Cascade(CascadeType.SAVE_UPDATE)
    @OneToMany(mappedBy = "container", orphanRemoval = true)
    public Collection<Item> getItems() { return items; }

    public void setItems(Collection<Item> items) { this.items = items; }
}

@Entity
public class Item extends AbstractEntity {
    private Container container;

    @ManyToOne(optional = false)
    public Container getContainer() { return container; }

    public void setContainer(Container container) { this.container = container; }
}

@Entity
public class FirstItemDetails extends AbstractEntity {
    private Item item;

    @OneToOne(optional = false)
    @Cascade({CascadeType.DELETE, CascadeType.REMOVE})
    public Item getItem() { return item; }

    public void setItem(Item item) { this.item = item; }
}

@Entity
public class SecondItemDetails extends AbstractEntity {
    private Item item;

    @OneToOne(optional = false)
    @Cascade({CascadeType.DELETE, CascadeType.REMOVE})
    public Item getItem() { return item; }

    public void setItem(Item item) { this.item = item; }
}

我遺漏了一些不必要的字段,因為它們最終沒有任何區別。 現在解決問題。 我想做的是這樣的:

public void removeItemFromContainer(Item item, Container container) {
    Transaction transaction = session.beginTransaction();
    container.getItems().remove(item);
    session.save(container);
    transaction.commit();
}

我從此功能期望的是從給定容器中物理刪除項目,並且由於我將orphanRemoval設置為true ,所以當我堅持使用容器時,它實際上會嘗試從數據庫中刪除項目。 這里的問題出在ItemItems實體上 ,它具有一個Foreign_key 約束,所以當提交被執行時,我得到:

org.hibernate.exception.ConstraintViolationException: could not execute statement
Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action; FK_FITEM_DETAILS_ITEM table: first_item_details
Caused by: org.hsqldb.HsqlException: integrity constraint violation: foreign key no action; FK_FITEM_DETAILS_ITEM table: first_item_details

對我來說最令人困惑的部分是,當我在數據庫的first_item_details表中物理地添加ON DELETE CASCADE而不是依靠休眠為我級聯時,一切正常。 但是,這種方法很容易出錯,因為如果在某些時候我就決定用我的任何我的個人信息實體的攔截事件監聽 ,它只是沒工作,所以我更喜歡讓Hibernate來處理它,而不需要到依靠手動的數據庫結構更改。

您將需要使Item與ItemDetails之間的關系成為雙向關系。 如果Item對這種關系一無所知,為什么要刪除相應的ItemDetail?

@Entity
public class Item extends AbstractEntity {
    private Container container;

    @OneToOne(mappedBy="item")
    @Cascade({CascadeType.DELETE, CascadeType.REMOVE})
    public ItemDetails itemDetails;
}

在此處查看類似的認可答案:

https://stackoverflow.com/a/7200221/1356423

當您注意到與此有關的一些問題時,您仍然應該可以通過使用JPA繼承來實現此目的,以便Item仍然可以與ItemDetails具有單一關系。 繼承策略將取決於您的數據庫結構:

http://en.wikibooks.org/wiki/Java_Persistence/Inheritance

更新后的代碼將如下所示:

@Entity
@Inheritance(/*defineStrategy*/)
//define discriminator column if required
public abstract class ItemDetails extends AbstractEntity {
    private Item item;

    @OneToOne(optional = false)
    @Cascade({CascadeType.DELETE, CascadeType.REMOVE})
    public Item getItem() { return item; }

    public void setItem(Item item) { this.item = item; }
}

@Entity
//define table or discriminator depending on strategy
public class FirstItemDetails extends ItemDetails {
    //map fields specific to thus sub-class
}

@Entity
//define table or discriminator depending on strategy
public class SecondItemDetails extends ItemDetails {
     //map fields specific to thus sub-class 
}

這也將帶來好處,即您不必在每個ItemDetails類中重復對Item的映射,但是如果您要為每個類使用表,則會以額外的聯接為代價。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM