1

我有一个与这里提出的问题相同的问题:how to define an inverse cascade delete on a many-to-one mapping in hibernate

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

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

这种级联似乎是一个基本功能,看到hibernate不支持它我有点失望:/

4

2 回答 2

2

您链接到的问题的答案是正确的。如果父级知道它的子级,Hibernate 只能在删除父级时删除子级。

唯一的解决办法是让ParentDAO的delete方法去搜索父级的所有子级,删除它们,然后再删除父级本身。

如果您担心 ParentDAO 不应该知道子级,您可以将其解耦,并让 ParentDAO 有一个已注册的 ParentDeletionListener 列表,在删除父级本身之前将调用该列表。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);
    }
}
于 2011-12-05T11:48:50.387 回答
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);
    }
}

我的抽象休眠实现可以通知观察者删除。

@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

于 2011-12-06T11:23:47.423 回答