Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA merge in a RESTful web application with DTOs and Optimistic Locking?

Tags:

java

rest

jpa

dto

web

My question is this: Is there ever a role for JPA merge in a stateless web application?

There is a lot of discussion on SO about the merge operation in JPA. There is also a great article on the subject which contrasts JPA merge via a more manual Do-It-Yourself process (where you find the entity via the entity manager and make your changes).

My application has a rich domain model (ala domain-driven design) that uses the @Version annotation in order to make use of optimistic locking. We have also created DTOs to send over the wire as part of our RESTful web services. The creation of this DTO layer also allows us to send to the client everything it needs and nothing it doesn't.

So far, I understand this is a fairly typical architecture. My question is about the service methods that need to UPDATE (i.e. HTTP PUT) existing objects. In this case we have these two approaches 1) JPA Merge, and 2) DIY.

What I don't understand is how JPA merge can even be considered an option for handling updates. Here's my thinking and I am wondering if there is something I don't understand:

1) In order to properly create a detached JPA entity from a wire DTO, the version number must be set correctly...else an OptimisticLockException is thrown. But the JPA spec says:

An entity may access the state of its version field or property or export a method for use by the application to access the version, but must not modify the version value[30]. Only the persistence provider is permitted to set or update the value of the version attribute in the object.

2) Merge doesn't handle bi-directional relationships ... the back-pointing fields always end up as null.

3) If any fields or data is missing from the DTO (due to a partial update), then the JPA merge will delete those relationships or null-out those fields. Hibernate can handle partial updates, but not JPA merge. DIY can handle partial updates.

4) The first thing the merge method will do is query the database for the entity ID, so there is no performance benefit over DIY to be had.

5) In a DYI update, we load the entity and make the changes according to the DTO -- there is no call to merge or to persist for that matter because the JPA context implements the unit-of-work pattern out of the box.

Do I have this straight?

Edit:

6) Merge behavior with regards to lazy loaded relationships can differ amongst providers.

like image 503
HDave Avatar asked Jan 03 '13 14:01

HDave


1 Answers

Using Merge does require you to either send and receive a complete representation of the entity, or maintain server side state. For trivial CRUD-y type operations, it is easy and convenient. I have used it plenty in stateless web apps where there is no meaningful security hazard to letting the client see the entire entity.

However, if you've already reduced operations to only passing the immediately relevant information, then you need to also manually write the corresponding services.

Just remember that when doing your 'DIY' update you still need to pass a Version number around on the DTO and manually compare it to the one that comes out of the database. Otherwise you don't get the Optimistic Locking that spans 'user think-time' that you would have if you were using the simpler approach with merge.

  1. You can't change the version on an entity created by the provider, but when you have made your own instance of the entity class with the new keyword it is fine and expected to set the version on it.

  2. It will make the persistent representation match the in-memory representation you provide, this can include making things null. Remember when an object is merged that object is supposed to be discarded and replaced with the one returned by merge. You are not supposed to merge an object and then continue using it. Its state is not defined by the spec.

  3. True.

  4. Most likely, as long as your DIY solution is also using the entity ID and not an arbitrary query. (There are other benefits to using the 'find' method over a query.)

  5. True.

like image 116
Affe Avatar answered Oct 02 '22 07:10

Affe