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.
Currently the methods that exists are (a nice summary can be
found at: http://stackoverflow.com/questions/161224/what-are-the-differences-between-the-different-saving-methods-in-hibernate)
·
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