NHibernate session maintains an identity map for all currently loaded (persisted) objects. Identity map uses the entity id as the key. In your case, your Id
is a simple int
value and since it's equal to 0
(by default) for newly created object, session.Merge()
can't find the matching persistent entity in session. Instead, a new row is added to database.
Read Ayende's post about cross-session operations for more in depth explanation.
In other cases, where you want to have a different notion of entity equality, you would override Equals()
and GetHashCode()
methods of your entity - i.e. to compare all properties, but I'm afraid, it won't help you in this case.
Just for the reference, here are some links about Equals()
and GetHashCode()
usage:
Is there a sample why Equals/GetHashCode should be overwritten in NHibernate?
NHibernate: Reasons for overriding Equals and GetHashCode
Edit
There are two options to update the row at database level:
You could do NHibernate update query, something along these lines:
Employee emp; // = your new employee instance
session.CreateQuery(
"update Employee set Property1 = :property1, ... " +
"where Idc = :idc, Ide = :ide")
.SetParameter("idc", emp.Idc)
.SetParameter("ide", emp.Ide)
.SetParameter("property1", emp.Property1)
// other properties
.ExecuteUpdate();
Also, you could use native SQL to do this: session.CreateSQLQuery("...").ExecuteUpdate();
Or you could load the entity first, update its properties and then save it:
Employee emp; // = your new employee instance
Employee oldEmployee = session.Query<Employee>()
.Where(x => x.Idc == emp.Idc)
.Where(x => x.Ide == emp.Ide)
.Single();
oldEmployee.Property1 = emp.Property1;
oldEmployee.Property2 = emp.Property2;
// other properties
session.SaveOrUpdate(oldEmployee);