Hibernate,单向ManyToOne以及对“On Delete Cascade”功能的渴望

时间:2011-12-05 11:17:04

标签: hibernate many-to-one hibernate-cascade

我遇到的问题与此处提出的问题相同:how to define an inverse cascade delete on a many-to-one mapping in hibernate

经过一段时间的搜索,我无法找到一个体面/干净的解决方案。我不能让父实体对子项有@OneToMany,因为它们位于不同的模块中。我想尝试在父级之前删除子级的EntityListener,但我不能再这样了,因为它们位于不同的模块中。

有谁知道这个干净的解决方案?我正在考虑使用AspectJ来监听来自ParentDao的delete方法的调用,但这不是一个干净的解决方案,我将不得不为每个与Parent类有这种关系的实体实现一个。

这种级联似乎是一个基本功能,我很沮丧地看到hibernate不支持它:/

2 个答案:

答案 0 :(得分:2)

您链接的问题的答案是正确的。如果父节点知道它的子节点,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);
    }
}

答案 1 :(得分:1)

根据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