Tuesday, July 16, 2013

Merge Update Save and filters

Merge Update Save and Filters


In sql there are three major types of actions: insert, update, delete.
Hibernate has a lot of functions that use these three actions. It is important to understand the difference between them, and when to use what.
·         delete()
·         persist()
·         save()
·         update()
·         saveOrUpdate()
·         merge()

Delete

The easiest is delete. This will delete the entity from the database. The object passed to the delete method can be either transient or persistent.  Since hibernate uses the id for the delete is does not make a difference.

Persist, Save

Both of these will generate an insert into the database. The save will return the id that was generated, where persist returns void. Persist should be used unless you need the id immediately, since in the case of save an insert is run with the method, while persist is optimized and will run the insert at the latest possible time when the id is needed.

Update

Update is the tricky part of hibernate and has the most options. The hibernate documentation writes the following about persistent objects:
Transactional persistent instances (i.e. objects loaded, saved, created or queried by the Session) can be manipulated by the application, and any changes to persistent state will be persisted when the Session is flushed.
This means as long as the transaction and session is open, any change to a persisted object will be updated in the database when the session is flushed (usually on commit but can be called explicitly).
In the case of detached objects, hibernate has the methods of update and merge.
Update is the simple one. Update will persist a detached object to the database. In the case that you do not know if you need an insert or update, you can use the method saveOrUpdate. This method will check the id of the object. If there is no id an insert will be generated else an updated will be generated.
In the case that you call update on an object (detached) that already has an instance in the session, hibernate will through an exception. This is since hibernate wants to let you know that two different changes have been made to the object (one in the session and the other detached). So the way hibernate lets you know is through an exception - NonUniqueObjectException.
A simple way to solve this issue if you want to ignore previous changes and persist the latest one, is to call evict on the session and remove the previous object. Then the update will succeed.

Merge

Merge knows to overcome the problem of update. Though as we will see merge is very sophisticated and needs to be used with caution. The documentation of hibernate is as follows:
o    if there is a persistent instance with the same identifier currently associated with the session, copy the state of the given object onto the persistent instance
o    if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance
o    the persistent instance is returned
o    the given instance does not become associated with the session, it remains detached

Thinks you must take into consideration:

Returned Object

Take care to save the result of the method, since the object in the parameter remains detached. Hibernate will update the internal object with your information but will not add it to the session since another one exits, this one will be returned to you.

Select issues

The next issue is that if your object is not in the session, hibernate will generate a select statement to get it. This can be a performance hit that you did not take into consideration if all you wanted was an update. This is especially true for the case that you have fields marked as eager, or in certain cases of *ToOne (hibernate will load them also with lazy annotation – if the foreign key is not using the id [primary key]), in this case hibernate will load the whole graph.
Another problem with the select of the merge is filters. If you are using filters to load your data, and on the merge you do not have the filters open, hibernate will generate the select for the merge but without the filters. This will cause an inconsistency of data.

Another problem with filters is the root object. Hibernate filters are activated only on connections (joins) to other objects. So if you have an object (a) that points to an object (b) that holds a collections (c’s). Loading A where b is lazy will cause hibernate to not use the filter on b, only on c. The simple solution to this is to add a join in the hql and then the filter will be added. But in the case of merge, the original hql will not be run. A standard load will be run with the eager and the filter will not affect the object b.

No comments:

Post a Comment