的正确和简单的方法是什么?更新 集合(如果它与 映射)全部删除孤儿通过它的“父”对象?
通过更新,我不仅仅意味着从集合中添加/删除项目,还包括更新项目属性的值(当然对于之前在集合中的那些项目)。
场景是有一个Parent
具有 Child
集合的对象对象,并且用户可以通过一种形式编辑 Children 集合 - 添加/删除子集合,还可以 编辑 child 的属性 (在同一表格上)。
基本上我想要这样的东西:
Parent parent = session.get(Parent.class, parentUI.getId());
parent.setChildren(parentUI.getChildren()); // parentUI is a DTO
session.saveOrUpdate(parent);
这不起作用,我理解原因,但在我看来,这在使用 hibernate 和开发 UI 应用程序时应该是一种非常常见的情况,所以我正在寻找一个(按书本)解决方案。
我正在使用 hibernate 3.6.10 和基于 XML 的配置。
这是相关的映射(我使用 ArrayList 来存储子集合):
<list name="children" cascade="all, delete-orphan">
<key column="parent_id" not-null="true"/>
<list-index column="ordinal" />
<one-to-many class="Child" />
</list>
如果重要的话,子对象也有以相同方式映射的集合,但我认为这无关紧要,因为这是一个与所描述的问题相同的问题。
顺便提一句。我为此浪费了一整天的时间,当然还检查了数十个与此非常相似的问题,但还没有找到合理的解决方案或解决此问题的模式。也许我错过了什么?
最佳答案
好吧,因为我没有找到按书本的解决方案,所以我首先通过在我的父对象上创建自定义方法来手动解决这个问题 parent.updateChildren(parentUI.getChildren())
它遍历旧集合,将其与 UI 中的更新集合进行比较并手动更新。不用说,这远非理想。
然后我的一位同事(Zoran Regvart)给了我一个机智的想法(考虑到我正在使用的技术,即 Spring MVC)来稍微改进一下。
想法是,如果提交更新父表单的表单,在 spring (web) binder 完成工作之前,我们可以从 DB 加载集合并将其设置为命令对象 (parentUI
),从而将其“种植”到由 spring binder 更新(换句话说,将集合更新过程委托(delegate)给他 - 他无论如何都会做的事情)。
这是(伪)代码:
@ModelAttribute("parentUI")
public ParentUI initParentUI(HttpServletRequest p_request) {
ParentUI parentUI = new ParentUI();
String parentId = p_request.getParameter("id");
if (parentId != null) { // indicates a form submit
Parent parent = session.get(Parent.class, parentUI.getId());
parentUI.setChildren(parent.getChildren());
}
return parentUI;
}
这样,当 spring binder 完成他的工作时,他将更新已经绑定(bind)到 Hibernate session 的集合。
这个解决方案也不是我很满意的东西,我还没有在很多情况下测试过,但对于我目前的需求(对我来说),它肯定是一种改进。
更新:此解决方法仅在 的情况下才方便。添加 新 child 或编辑 他们的属性。对于 的情况删除 child 或 更改订单最好避免它,因为它会增加复杂性。
关于Hibernate - 更新与级联类型 all-delete-orphan 映射的集合的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20245497/