How to control JPA persistence in Wicket forms?

I am building an application using JPA 2.0 (implementation of Hibernate), Spring and Wicket. Everything works, but I'm worried that my form behavior is based on side effects.

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

My concern is the presentation of form. My form is currently passing the result of form.getModelObject() to a service method annotated with @Transactional . Since the object inside the model is still bound to the entity manager, @Transactional notes @Transactional sufficient to commit the changes.

This is normal until I have several forms working on the same object, each of which modifies a subset of the fields. And yes, they can be available at the same time. I thought of several options, but I would like to know any ideas that I missed, and recommendations for managing this for long-term maintainability:

  • Fragment my entity into subcomponents corresponding to the editing forms, and create a master object linking them together in @OneToOne . Causes an ugly table design and makes it difficult to change forms later.
  • Detach the object that it immediately loaded with the LoadableDetachableModel and manually merge the correct fields at the service level. To manage lazy loading, specialized versions of the model for each form may be required to ensure that the correct sub-objects are loaded.
  • Cloning an object into a local copy when creating a model for the form, and then manually merging the correct fields in the service layer. Implementation of multiple copy constructors / cloning methods is required.
  • Use the Hibernate dynamicUpdate parameter only to update the changed fields of an object. Causes non-standard JPA behavior throughout the application. It does not appear in the damaged code and causes a strong binding to the Hibernate implementation.
+4
source share
2 answers

EDIT

The obvious solution is to lock the object (i.e. the string) when loading it to bind the form. This ensures that the lock request reads / binds / writes cleanly, without simultaneously writing in the background. This is not ideal, so you will need to weigh potential performance issues (concurrent recording level).

In addition, considering that you are satisfied with the “latest record successes” in your property subgroups, Hibernate “dynamicUpdate” will seem like the smartest solution if you don’t think about switching ORMs any time soon. It seems strange to me that the JPA does not seem to offer anything that allows you to update only dirty fields and most likely it will be in the future.

Optional (my original answer)

Orthogonally to ensure that the transaction opens when your model loads an object to bind the form. The problem is that the properties of the objects are updated at this point and outside the transaction, which leaves the JPA object in an undefined state.

The obvious answer, as Adrian says in his comment, is to use a traditional transaction filter for each request. This ensures that all operations in the request occur in a single transaction. However, it will definitely use the database connection on every request.

There's a more elegant solution with code here . This method is to lazily create an instance of entitymanager and start a transaction only when necessary (i.e. when the first call to EntityModel.getObject () occurs). If a transaction is open at the end of the request cycle, it is committed. The advantage of this is that the connection to the database has never been wasted.

In the above implementation, the RequestCycle calibration object is used (note that this is slightly different in version 1.5), but the whole implementation is actually quite general, so you can use it (for example) using a gate through the servlet. Filter.

+3
source

After some experimentation, I came up with an answer. Thanks to @artbristol who pointed me in the right direction.

  • I set a rule in my architecture: DAO persistence methods should only be called to preserve individual objects. If the object is attached, the DAO throws an IllegalStateException . This helped keep track of any code that modified entities outside the transaction.
  • Then I changed my LoadableDetachableModel to two options. The classic version, used to view read-only data, returns an object from the JPA that will support lazy loading. The second option for use in form bindings uses Dozer to create a local copy.
  • I expanded the DAO base to have two save options. One saves the entire object with merge , and the other uses Apache Beanutils to copy the property list.

This at least avoids duplicate code. The downside is the requirement to configure Dozer so that it does not pull out the entire database using lazy loaded links and having even more code that references properties by name, eliminating type safety.

0
source

Source: https://habr.com/ru/post/1344244/


All Articles