Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

JPA Optimistic Concurrency for Detached Object

 
Frankie Fuentes
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi everyone,

Is there a way to ask if a detached object is outdated or not? (within an EJB call where entity manager is available of course)

My entity has a version column. Say I have a customer who ordered a product he saw on a web page. Upon submission of order, I would pass the detached product (which the customer has seen on the page and which might be outdated) to an EJB instead of just product ID so I could check what the customer actually saw when he submitted his order. If don't pass the product to the EJB, there's no way I could make sure that the customer has placed an order on a product that is not outdated. Is there a proper way of preventing the customer from ordering a product that is outdated?

The first thing occurred to me is to keep the detached entity, look it up using entity manager, and compare the version of retrieved persistent product with the detached product. Is this the right thing to do? If yes, please, at least say so.

In short, I want to prevent the customer from accidentally placing an order on a product with a new price that he hasn't seen yet.

Thanks!
 
Sai Hegde
security forum advocate
Ranch Hand
Posts: 212
1
Android Flex Google App Engine
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your persistence provider should be able to detect stale versions. This is pretty much a common use case.
 
Frankie Fuentes
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sai Hegde wrote:Your persistence provider should be able to detect stale versions. This is pretty much a common use case.


Thanks Sai. However it can only detect stale objects that are persistent or objects that you plan on making persistent. In my case, I want to be able to know if the product is stale or not without trying to invoke merge() operation on it. Obviously we don't want customers to be updating the products every time they place an order. You can't even call lock() on it since it is a detached object.

I'm not sure if I got your point clearly but in my case, I'm letting a customer to place an order on a product. This operation should not perform any update operation on the selected product but only inspect if it is stale or not so the customer will get notified that the product has changed since the last time the customer has seen the product on the web page, probably before he clicked on the submit button.
 
James Sutherland
Ranch Hand
Posts: 553
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
JPA supports this through optimistic read locks. A read lock will check the lock, but not update it.

See,
http://en.wikibooks.org/wiki/Java_Persistence/Locking#Read_and_Write_Locking
 
Frankie Fuentes
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks James but the example shown uses persistent entities (as far as I could understand). In my case I should use a detached instance and not look it up again using entityManager.find(). I should be able to know if the detached object is up to date or not.

Here's why I need a detached entity instead of a persistent one:

User sees a product.
User places an order on a product
The presentation layer will pass this product instance that the user saw on the web page to the EJB (service layer)
The EJB should be able to identify if the product that the user has seen and placed an order on is up to date with the database
If the detached product instance is not up to date, then inform the presentation layer that the product that the user ordered has changed.

Sorry if I couldn't get my point clearly explained.

What I'm trying to achieve here is to prevent the customer from placing an order on a product that has changed its price from the last time the customer has seen it. To do this, I would need to pass the product instance itself that the user saw on the web page. Using EntityManager.find() would be like refreshing the product. What I have in mind is to use EntityManager.find() to look up the latest version of the product and compare the version number of that persistent object to the detached product instance. I'm not really sure if this is the proper way of doing things.

Much appreciated.
 
Sai Hegde
security forum advocate
Ranch Hand
Posts: 212
1
Android Flex Google App Engine
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Call a session.refresh(product) to check if the price has changed from what you had displayed to the user. Business logic can then follow...
 
Frankie Fuentes
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Sai, so far looks like there are no other options but to use logic and manually compare the values.
I think calling refresh(product) will make comparing impossible unless you first create a clone of that instance and then call refresh so you could make comparison.

I just wasn't so sure if that's the "right" way. Maybe James was trying to tell me just to do that and at the same time use optimistic lock while comparing the version property or the price whichever is appropriate.

I would still want to hear from James.
 
James Sutherland
Ranch Hand
Posts: 553
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You could either call find() check the version matches the detached object, then get a read-lock on the object to ensure there are no updates until the commit of the transaction.

Or you could just call merge() on the object, and read-lock it, if the version is the same then there should be no changes merged, if it is different, then the update will fail anyway.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic