我遇到了一个和这里一样的问题:如何在hibernate中的多对一映射上定义反向级联删除
搜索了一段时间后,我找不到一个像样的/干净的解决方案。我不能让父实体有一个@OneToMany到子实体,因为它们在不同的模块。我想尝试EntityListener,将删除父之前的孩子,但我不能,因为,再一次,他们在不同的模块。
有人知道一个干净的解决方案吗?我正在考虑使用AspectJ来监听来自ParentDao的删除方法的调用,但这不是一个干净的解决方案,我将不得不为每个与Parent类有这种关系的实体实现一个。
这种级联似乎是一种基本特性,看到hibernate不支持它,我有点失望:/
你链接到的问题的答案是正确的。如果父类知道它的子类,Hibernate只能在删除父类时删除子类。
唯一的解决方案是使用ParentDAO的delete方法来搜索父类的所有子类,删除它们,然后删除父类本身。
如果您关心的是ParentDAO不应该知道子对象,您可以使它解耦,并让ParentDAO拥有一个注册的ParentDeletionListeners列表,该列表将在删除父对象本身之前被调用。ParentDAO只知道这个ParentDeletionListener接口,并允许注册多个侦听器。在启动应用程序时,为每一种子类型注册一个侦听器,并让侦听器删除子类型:
public interface ParentDeletionListener {
void parentWillBeDeleted(Parent parent);
}
public class SomeChildParentDeletionListener implements ParentDeletionListener {
// ...
public void parentWillBeDeleted(Parent parent) {
// search for every SomeChild linked to the given parent
// and delete them
}
}
public class ParentDAO {
private List<ParentDeletionListener> listeners = new CopyOnWriteArrayList();
public void addParentDeletionListener(ParentDeletionListener listener) {
this.listeners.add(listener);
}
public void deleteParent(Parent p) {
for (ParentDeletionListener listener : listeners) {
listener.parentWillBeDeleted(parent);
}
session.delete(parent);
}
}
根据JB Nizet的回答,我将我的DAO更改为具有DeleteOperationListener(我的基本DAO实现基于"不要重复DAO"[1])。这样我就有了一个通用的解决方案,以防我再次遇到同样的情况。结构如下所示:
public interface GenericDao<T, PK extends Serializable> {
// CRUD methods
// delete operation listeners.
void addDeleteListener(DeleteOperationListener<T, PK> deleteOperationListener);
public interface DeleteOperationListener<T> {
void preDelete(T entity);
void posDelete(T entity);
}
}
和我的抽象hibernate实现,我可以通知观察者关于删除。
@Override
public void delete(T entityToDelete) {
notifyPreDelete(entityToDelete);
this.getHibernateTemplate().delete(entityToDelete);
notifyPosDelete(entityToDelete);
}
现在我有了一个不同的类,它可以在不更改dao的情况下处理子节点的删除:
@Service
public class ParentModificationListener
implements GenericDao.DeleteOperationListener<Parent> {
private ChildDao childDao;
@Autowired
public ParentModificationListener(ChildDao childDao, ParentDao parentDao) {
this.childDao = childDao;
parentDao.addDeleteListener(this);
}
@Override
public void preDelete(Parent parent) {
this.childDao.deleteChildrenFromParent(parent);
}
@Override
public void posDelete(Parent parent) {
// DO NOTHING
}
}
[1] http://www.ibm.com/developerworks/java/library/j-genericdao.html