Hibernate、单向 ManyToOne 以及对“删除级联”的渴望特征

发布于 2024-12-19 13:54:23 字数 468 浏览 2 评论 0原文

我遇到的问题与此处提出的问题相同: 如何在休眠中的多对一映射上定义反向级联删除

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

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

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

I have a problem that's equal to the one presented here: how to define an inverse cascade delete on a many-to-one mapping in hibernate

After searching for a while I can't find a decent/clean solution for this. I can't have the parent entity have an @OneToMany to the child, because they are at different modules. I wanted to try the EntityListener that would delete the children before the parent is, but I can't because, again, they are at different modules.

Does anyone know a clean solution to this? I am thinking about to use AspectJ to listen to the call of the delete method from the ParentDao, but this is not a clean solution and I will have to implement one for each entity that have this kind of relation to the Parent class.

This kind of cascade seems to be a basic feature and I am kind dissapointed in seeing that hibernate does not support it :/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忘你却要生生世世 2024-12-26 13:54:23

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

唯一的解决方案是使用 ParentDAO 的删除方法来搜索父级的所有子级,删除它们,然后删除父级本身。

如果您担心 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);
    }
}

The answer of the question you linked to is correct. Hibernate can only delete the children when deleting the parent if the parent knows about its children.

The only solution is to have the ParentDAO's delete method to search for all the children of the parent, delete them, and then delete the parent itself.

If your concern is that the ParentDAO shouldn't know about the children, you could make it decoupled, and have the ParentDAO have a list of registered ParentDeletionListeners, which would be invoked before deleting the parent itself. The ParentDAO know only about this ParentDeletionListener interface, and allows registering several listeners. When starting the application, register a listener for every kind of child, and have the listener delete the children:

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);
    }
}
ゞ记忆︶ㄣ 2024-12-26 13:54:23

基于 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]

Based on JB Nizet answer I changed my DAO to have a DeleteOperationListener (My base DAO implementation is based on "Don't Repeat the DAO"[1].) In this way I have a generic solution in case I find myself in the same situation again. The structure looks like this:

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);
    }
}

And my abstract hibernate implementation I can notify the observers about the delete.

@Override
public void delete(T entityToDelete) {
    notifyPreDelete(entityToDelete);
    this.getHibernateTemplate().delete(entityToDelete);
    notifyPosDelete(entityToDelete);
}

And now I have a different class that handles the deletion of the children without needing to change the DAOs:

@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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文