In NHibernate 3.1, ISession.SaveOrUpdateCopy()
has been marked as deprecated. The documentation suggests using Merge()
instead. The documentation for each is as follows:
SaveOrUpdateCopy(object obj)
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved or does not exist in the database, save it and return it as a newly persistent instance. Otherwise, the given instance does not become associated with the session.
Merge(object obj)
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with
cascade="merge"
.
The semantics of this method are defined by JSR-220.
They look nearly identical to me, but there are bound to be some subtleties involved. If so, what are they?
Once save/update is done, the object DOES NOT reflect the change. The returned object reflects the changes, and it is attached to hibernate session. MERGE method offers greater flexibility when it comes to saving data objects, since you need not worry about attaching object to Session.
You should use Merge() if you are trying to update objects that were at one point detached from the session, especially if there might be persistent instances of those objects currently associated with the session. Otherwise, using SaveOrUpdate() in that case would result in an exception.
Hibernate handles persisting any changes to objects in the session when the session is flushed. update can fail if an instance of the object is already in the session. Merge should be used in that case. It merges the changes of the detached object with an object in the session, if it exists.
Hibernate merge can be used to update existing values, however this method create a copy from the passed entity object and return it. The returned object is part of persistent context and tracked for any changes, passed object is not tracked. This is the major difference with merge() from all other methods.
SaveOrUpdateCopy is now considered obsolete and thus Merge is meant to take over for it (hence its extreme similarity).
They are pretty much the same except I don't think those cascade options were available with SaveOrUpdateCopy. However, that point is moot as Merge should be method you use.
UPDATE: I went in to the source code of NHibernate just to make sure they are as similar as I was thinking and here is what I found.
Both Merge and SaveOrUpdateCopy have very similar implementations:
public object Merge(string entityName, object obj)
{
using (new SessionIdLoggingContext(SessionId))
{
return FireMerge(new MergeEvent(entityName, obj, this));
}
}
public object SaveOrUpdateCopy(object obj)
{
using (new SessionIdLoggingContext(SessionId))
{
return FireSaveOrUpdateCopy(new MergeEvent(null, obj, this));
}
}
Their FireXXXX methods are also very similar:
private object FireMerge(MergeEvent @event)
{
using (new SessionIdLoggingContext(SessionId))
{
CheckAndUpdateSessionStatus();
IMergeEventListener[] mergeEventListener = listeners.MergeEventListeners;
for (int i = 0; i < mergeEventListener.Length; i++)
{
mergeEventListener[i].OnMerge(@event);
}
return @event.Result;
}
}
private object FireSaveOrUpdateCopy(MergeEvent @event)
{
using (new SessionIdLoggingContext(SessionId))
{
CheckAndUpdateSessionStatus();
IMergeEventListener[] saveOrUpdateCopyEventListener = listeners.SaveOrUpdateCopyEventListeners;
for (int i = 0; i < saveOrUpdateCopyEventListener.Length; i++)
{
saveOrUpdateCopyEventListener[i].OnMerge(@event);
}
return @event.Result;
}
}
The methods are exactly the same except they draw on different event listener lists, but even the types of the lists (IMergeEventListener) are the same!
Looking at the listener lists, they are both initialized with a default listener. The default listener for the Merge listen handlers is of type DefaultMergeEventListener while the SaveOrUpdateCopy is DefaultSaveOrUpdateCopyEventListener. Thus, the difference between them is just the difference in these two implementations (that is if you keep the default listener, which is 99% of the time).
However, the real interesting fact IS the difference in implementation. If you look at DefaultSaveOrUpdateCopyEventListener you get this:
public class DefaultSaveOrUpdateCopyEventListener : DefaultMergeEventListener
{
protected override CascadingAction CascadeAction
{
get { return CascadingAction.SaveUpdateCopy; }
}
}
This means the default behavior for Merge and SaveOrUpdateCopy only differs in the cascading actions, everything else is exactly the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With