aspose file tools*
The moose likes EJB Certification (SCBCD/OCPJBCD) and the fly likes Entitymanager.refresh doubt Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » EJB Certification (SCBCD/OCPJBCD)
Bookmark "Entitymanager.refresh doubt" Watch "Entitymanager.refresh doubt" New topic
Author

Entitymanager.refresh doubt

Anish Mathur
Greenhorn

Joined: Jun 30, 2008
Posts: 9
In EJB 3 in Action sec 9.3.6
an example is given to undo changes made to Item entity and return fresh entity data from DB. The code to that is

<blockquote>code:
<pre name="code" class="core">public item undoItemChanges(Item item) {
entityManager.refresh(entityManager.merge(item));
return item;
}
</pre>
</blockquote>

The merge operation is performed first in the undoItemChanges method because the refresh method only works on managed entities.


My doubt is, if the item object has been modified out the presitence context and then if merge operation is called, the changes made to Item object will be persisted to DB. Now, if refresh is called, it will get the modified data not the data which existed before calling merege. So, this method will not do the undo functionality.
Please help me in understanding how refresh and merge work in this example?
Aleksander Zielinski
Ranch Hand

Joined: Nov 11, 2005
Posts: 127
As you quoted, merge operation is performed only to make the instance managed as it was detached. Changes are persisted when a transaction commits, so no changes are written to the database yet. Then refresh is made to update object state with database information.

However the problem lies somewhere else. Merge method returns either a new instance or an existing managed version from the persistence context. Our object is a detached instance therefore we'll get a new object. The new object will be refreshed and since the undoItemChanges method returns reference to our old detached instance we will be working with detached instance with state that has not been refreshed with current database information.

It should look like this:

<blockquote>code:
<pre name="code" class="core">
public Item undoItemChanges(Item item) {
Item refreshedItem = entityManager.merge(item);
entityManager.refresh(refreshedItem);
return refreshedItem;
}
</pre>
</blockquote>
[ July 16, 2008: Message edited by: Aleksander Zielinski ]
E Lievaart
Greenhorn

Joined: Jul 06, 2008
Posts: 28
An addition on the working of merge and refresh:

First merge is invoked.
The changes will be applied to the persistence context.
In other words the in memory object managed by the entity manager is updated.
Second, refresh is invoked.
The refresh operation reads the Object from the database.
The database still contains the old values, because no flush has yet occured.

The merge operation does not write directly to the database.
The database remains unchanged until a flush occurs.
So the refresh method still reads the old values.

The spec does not specify if the refresh method reads flushed data or only committed data.
The JPA provider can flush data at any given time.
So there is a (very small) chance that the object is merged, a flush occurs and the refresh reads the merged data and not the previous data.
Vinay Nath
Ranch Hand

Joined: Jul 06, 2008
Posts: 85
hi Anish,

first merge will take all your changes done in detached state and copy them or create a new managed item object with those changes, so now your item is managed with Persuitent context, now if you do refresh on this, all the data from database will get copied into your managed item object.

Remember this step is not necessary if your item object is already managed in Persistent context. Merge is only needed in this case to make it managed.


SCDJWS 5.0, SCBCD 5.0, SCWCD 5.0, SCJP 5.0
Anish Mathur
Greenhorn

Joined: Jun 30, 2008
Posts: 9
I tried both the EJB3 book example and solution suggested by Aleksander. The book example doesn't work but Aleksander's code works.

Now I am thinking if we do

Item refreshedItem = entityManager.merge(item);
.
.
long time consuming code
.
.
//decission is taken the item should be refreshed with the data from database
entityManager.refresh(refreshedItem);

Then as Lievaart said there is a chance that the object is merged, a flush occurs and the refresh reads the merged data and not the previous data.

The other way in which undo can be implemented is by using a find query based on primary key.

public Item undoItemChanges(Item item) {
Item refreshItem = em.createQuery("Select i from Item i where i.pkCol = :ItemPK")
.setParameter("ItemPK", item.pkCol).getSingleResult();
return refreshItem;
}

Just after writing this code I checked on net, I found following article
http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t_1.html
check section "Getting fresh results from database"
krishna bulusu
Ranch Hand

Joined: Aug 28, 2006
Posts: 185
Hi Anish,
Good Question.
Read the page No: 327 closely in EJB3 in Action.
Following is a snippet from that page:

"You should remember that like all attached entities, the entity passed to the
merge method is not necessarily synchronized with the database immediately, but it is guaranteed to be synchronized with the database sooner or later."

And if you observe the diagram there, the merge would attach the object to the persistent context not to the database. so, in your case, once the item object attached to the persistent context, the refresh method would update the data in the item object with the data in the database which is not updated yet due to the merge operation.
same the case with the remove method also.

In the above code(the latest post), I think that is not a good idea to refresh the data with the database. Always it is better to use the API method(refresh()) than use the custom method. Any comments?


Thanks&Regards, Krishna.
SCJP1.4, SCWCD1.4, SCBCD 5.0
Vinay Nath
Ranch Hand

Joined: Jul 06, 2008
Posts: 85
the query could be a bad idea if you are using CMT with extended persistent context because executing this query will by default call flush() to database and any other managed entities will get written to database.

refresh() is a better option as also stated by krishna.
Sergio Tridente
Ranch Hand

Joined: Mar 22, 2007
Posts: 329

Originally posted by Anish Mathur:
I tried both the EJB3 book example and solution suggested by Aleksander. The book example doesn't work but Aleksander's code works.


If you give a more attentive look at both code snippets you'll understand why:


In this case the returned reference (item) is still refering to the unmanaged entity (the one passed as parameter).

While in Aleksander's case:

In this case, after calling merge() we get a reference to a managed entity object (refreshedItem). Afterwards, when calling refresh() on that object's reference, the entity gets refreshed and our method returns the merged and now refreshed object's reference.

I hope I was clear enough.


SCJP 1.4 (88%) - SCJP 5.0 Upgrade (93%) - SCWCD 1.4 (97%) - SCBCD 5.0 (98%)
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
 
subject: Entitymanager.refresh doubt