我目前的设置类似于:
@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,因此当我持久化我的容器时,它实际上确实尝试从数据库中删除该项目。这里的问题在于具有 foreign_key 约束的ItemDetails 实体,因此在运行提交时我得到:
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而不是依靠休眠为我级联时,一切正常。但是这种方法很容易出错,因为如果在某个时候我决定为我的任何详细信息实体使用拦截器或eventListener ,它根本不起作用,所以我更愿意让 hibernate 来处理它而不是需要依靠手动数据库结构更改。