4

如果集合被它的“父”对象映射为all-delete-orphan ,那么更新集合的正确和简单的方法是什么? 通过更新,我不仅仅意味着从集合中添加/删除项目,还包括更新项目属性的值(当然对于之前在集合中的那些项目)。

场景是有一个Parent对象具有一组Child对象,并且有一个表单,用户可以通过该表单编辑 Children 集合 - 添加/删除子项,但也可以编辑子项的属性(在同一表单上)。

基本上我想要这样的东西:

Parent parent = session.get(Parent.class, parentUI.getId());
parent.setChildren(parentUI.getChildren());  // parentUI is a DTO
session.saveOrUpdate(parent);

这不起作用,我理解原因,但在我看来,这应该是使用休眠和开发 UI 应用程序时非常常见的情况,所以我正在寻找一个(按书本)解决方案。

我正在使用休眠 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>

如果重要的话,子对象也有以相同方式映射的集合,但我认为这不相关,因为这是一个与所描述的问题相同的问题。

顺便提一句。我为此浪费了一整天的时间,当然还检查了数十个与此非常相似的问题,但还没有找到合理的解决方案或解决此问题的模式。也许我错过了什么?

4

1 回答 1

1

好吧,因为我没有找到按书本的解决方案,所以我首先通过在我的父对象上创建一个自定义方法来手动parent.updateChildren(parentUI.getChildren())解决这个问题,该方法遍历旧集合,将它与 UI 中的更新后的集合进行比较并手动更新它。不用说,这远非理想。

然后我的一位同事(Zoran Regvart)给了我一个机智的想法(考虑到我正在使用的技术,即 Spring MVC)来稍微改进一下。
想法是,如果提交更新父级的表单,在 spring (web) binder 完成工作之前,我们可以从 DB 加载集合并将其设置为命令对象 ( parentUI),从而“种植”它以更新弹簧活页夹(换句话说,将集合更新过程委托给他——他无论如何都会做的事情)。

这是(伪)代码:

@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 完成他的工作时,他将更新已经绑定到 Hibernate session 的集合。

这个解决方案也不是我很满意的东西,我还没有在很多情况下测试过,但对于我目前的需求(对我来说),它肯定是一种改进。

更新:此解决方法仅在添加新子项或编辑其属性的情况下才方便。对于删除子级或更改其顺序的 情况,最好避免,因为它会增加复杂性。

于 2013-12-16T16:37:33.733 回答