如何控制Wicket表单中的JPA持久性? [英] How to control JPA persistence in Wicket forms?

查看:56
本文介绍了如何控制Wicket表单中的JPA持久性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JPA 2.0(Hibernate实现),Spring和Wicket构建应用程序.一切正常,但是我担心我的表单行为是基于副作用的.

I'm building an application using JPA 2.0 (Hibernate implementation), Spring, and Wicket. Everything works, but I'm concerned that my form behaviour is based around side effects.

第一步,我正在使用OpenEntityManagerInViewFilter.我的域对象由LoadableDetachableModel获取,该LoadableDetachableModel在其load方法中执行entityManager.find().在我的表单中,我在该模型周围包裹了CompoundPropertyModel来绑定数据字段.

As a first step, I'm using the OpenEntityManagerInViewFilter. My domain objects are fetched by a LoadableDetachableModel which performs entityManager.find() in its load method. In my forms, I wrap a CompoundPropertyModel around this model to bind the data fields.

我关心的是表单提交操作.目前,我的表单将form.getModelObject()的结果传递到带@Transactional注释的服务方法中.由于模型内的实体仍附加在实体管理器上,因此@Transactional批注足以提交更改.

My concern is the form submit actions. Currently my form submits pass the result of form.getModelObject() into a service method annotated with @Transactional. Because the entity inside the model is still attached to the entity manager, the @Transactional annotation is sufficient to commit the changes.

这很好,直到我有对同一实体进行操作的多种形式,每种形式都改变了字段的一个子集.是的,可以同时访问它们.我想到了一些选择,但是我想知道我错过的任何想法以及为实现长期可维护性而进行管理的建议:

This is fine, until I have multiple forms that operate on the same entity, each of which changes a subset of the fields. And yes, they may be accessed simultaneously. I've thought of a few options, but I'd like to know any ideas I've missed and recommendations on managing this for long-term maintainability:

  • 将我的实体分为与编辑表单相对应的子组件,然后创建一个主实体,将它们链接在一起成为@OneToOne关系. 导致表格设计难看,并且以后很难更改表格.
  • 立即将实体由LoadableDetachableModel加载,然后将其分离,然后在服务层中手动合并正确的字段. 难以管理延迟加载,可能需要为每种形式的模型提供专门的版本,以确保加载正确的子实体.
  • 在为表单创建模型时,将实体克隆到本地副本中,然后在服务层中手动合并正确的字段. 需要实现许多复制构造函数/克隆方法.
  • 使用Hibernate的dynamicUpdate选项仅更新实体的更改字段. 在整个应用程序中导致非标准的JPA行为.在受影响的代码中不可见,并与Hibernate实现紧密相关.
  • Fragment my entity into sub-components corresponding to the edit forms, and create a master entity linking these together into a @OneToOne relationship. Causes an ugly table design, and makes it hard to change forms later.
  • Detach the entity immediately it's loaded by the LoadableDetachableModel, and manually merge the correct fields in the service layer. Hard to manage lazy loading, may need specialised versions of the model for each form to ensure correct sub-entities are loaded.
  • Clone the entity into a local copy when creating the model for the form, then manually merge the correct fields in the service layer. Requires implementation of a lot of copy constructors / clone methods.
  • Use Hibernate's dynamicUpdate option to only update changed fields of the entity. Causes non-standard JPA behaviour throughout the application. Not visible in the affected code, and causes a strong tie to Hibernate implementation.

推荐答案

编辑

显而易见的解决方案是在加载实体以进行表单绑定时锁定该实体(即行).这将确保锁拥有请求可以干净地读取/绑定/写入,而在后台不会发生并发写入.这不是理想的选择,因此您需要权衡潜在的性能问题(并发写入的级别).

The obvious solution is to lock the entity (i.e. row) when you load it for form binding. This would ensure that the lock-owning request reads/binds/writes cleanly, with no concurrent writes taking place in the background. It's not ideal, so you'd need to weigh up the potential performance issues (level of concurrent writes).

除此之外,假设您对属性子组的最后写入胜利"感到满意,那么Hibernate的"dynamicUpdate"似乎是最明智的解决方案,除非您打算尽快转换ORM.我感到奇怪的是,JPA似乎没有提供任何仅允许您更新脏字段并发现将来可能会更新的字段.

Beyond that, assuming you're happy with "last write wins" on your property sub-groups, then Hibernate's 'dynamicUpdate' would seem like the most sensible solution, unless your thinking of switching ORMs anytime soon. I find it strange that JPA seemingly doesn't offer anything that allows you to only update the dirty fields, and find it likely that it will in the future.

其他(我的原始答案)

与此正交的是如何确保当模型加载实体以进行表单绑定时打开事务.令人担心的是,此时实体属性会更新,并且在事务之外,这会使JPA实体处于不确定状态.

Orthogonal to this is how to ensure you have a transaction open when when your Model loads an entity for form binding. The concern being that the entities properties are updated at that point and outside of transaction this leaves a JPA entity in an uncertain state.

正如阿德里安(Adrian)在评论中所说,显而易见的答案是使用传统的按请求交易"过滤器.这保证了请求中的所有操作都在单个事务中发生.但是,它将肯定在每个请求上使用数据库连接.

The obvious answer, as Adrian says in his comment, is to use a traditional transaction-per-request filter. This guarantees that all operations within the request occur in single transaction. It will, however, definitely use a DB connection on every request.

还有一个更优雅的解决方案,其代码为此处.该技术是延迟实例化实体管理器,并仅在需要时(即,在第一次EntityModel.getObject()调用发生时)才开始事务.如果在请求周期结束时有一个事务打开,则将其提交.这样做的好处是,绝不会浪费任何数据库连接.

There's a more elegant solution, with code, here. The technique is to lazily instantiate the entitymanager and begin the transaction only when required (i.e. when the first EntityModel.getObject() call happens). If there is a transaction open at the end of the request cycle, it is committed. The benefit of this is that there are never any wasted DB connections.

给定的实现使用了wicket RequestCycle对象(请注意,在v1.5及更高版本中稍有不同),但是整个实现实际上是相当通用的,因此,您可以(例如)通过Servlet过滤器将其与wicket一起使用

The implementation given uses the wicket RequestCycle object (note this is slightly different in v1.5 onwards), but the whole implementation is in fact fairly general, so and you could use it (for example) outwith wicket via a servlet Filter.

这篇关于如何控制Wicket表单中的JPA持久性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆