【发布时间】:2011-03-18 09:41:32
【问题描述】:
我正在使用 JPA 2.0(Hibernate 实现)、Spring 和 Wicket 构建应用程序。一切正常,但我担心我的表单行为是基于副作用。
作为第一步,我使用的是OpenEntityManagerInViewFilter。我的域对象由LoadableDetachableModel 获取,它在其load 方法中执行entityManager.find()。在我的表单中,我在这个模型周围包裹了一个CompoundPropertyModel 来绑定数据字段。
我关心的是表单提交操作。目前,我的表单提交将form.getModelObject() 的结果传递到使用@Transactional 注释的服务方法中。因为模型内部的实体仍然附加到实体管理器,@Transactional 注释足以提交更改。
这很好,直到我有多个表单对同一个实体进行操作,每个表单都会更改字段的子集。是的,它们可以同时访问。我已经想到了几个选项,但我想知道我错过的任何想法以及有关管理它以实现长期可维护性的建议:
- 将我的实体分割成对应于编辑表单的子组件,并创建一个主实体将它们链接在一起形成
@OneToOne关系。 导致表格设计难看,并且以后很难更改表格。 - 立即分离由
LoadableDetachableModel加载的实体,并手动合并服务层中的正确字段。 很难管理延迟加载,可能需要为每个表单提供专门的模型版本,以确保加载正确的子实体。 - 在为表单创建模型时将实体克隆到本地副本,然后在服务层中手动合并正确的字段。 需要实现很多复制构造函数/克隆方法。
- 使用 Hibernate 的
dynamicUpdate选项仅更新实体的更改字段。 在整个应用程序中导致非标准 JPA 行为。在受影响的代码中不可见,并导致与 Hibernate 实现密切相关。
【问题讨论】:
-
欢迎来到我的噩梦 ;),我们遇到了同样的问题。如果您使用带有就地编辑的列表/表格并将新条目添加到列表中,您也会遇到此问题。由于 JPA merge() 返回一个新副本并且您可能会保留 UI 层中的陈旧对象。我认为唯一干净的方法是使用 DTO(或您从不附加到 EM 的 JPA 实体)。许多丑陋的代码来来回复制更改。我在这里期待答案。当我在这里或在检票口 ML 上问时,我从来没有得到过一次 ..
-
如果您使用克隆选项,您可以考虑使用像 Dozer 这样的 bean 映射器来节省您编写代码的时间。但是不要它如何与延迟加载的 bean 属性交互。
-
我现在正在尝试 Dozer 方法 - 我的
@ElementCollection列表字段似乎有问题,可能是由于缺少公共设置器。 -
同一页面中的多个表单,还是多个窗口?我没有发现问题...“同时”是什么意思?
-
@tetsuo - 我的意思是不同会话中的多个用户。举个简单的例子,Alice 打开联系地址表单,而 Bob 打开针对同一客户的定价表单。如果 Alice 先点击“保存”,那么当 Bob 点击“保存”时,她的变化会发生什么?实际情况稍微复杂一些,因为有些表单是具有就地编辑功能的表格。