0

Having a NHibernate entity:

public class Employee
{
    public virtual int Id { get; set; }
    public virtual int Idc { get; set; }
    public virtual int Ide { get; set; }
    .
    . other properties
    .
}

with Id mapped as:

<id name="Id" unsaved-value="0">
    <generator class="sequence">
        <param name="sequence">employee_id_seq</param>
    </generator>
</id>

If I populate all properties of a new Employee except Id and then call session.Merge() it just creates another row with all properties identical to the original row except Id instead of merging with the existing employee.

Is it possible to do instead an update at database level on the row corresponding to those properties? Idc + Ide together are unique so it should be possible to identify the row to be merged.

Thanks for your help!

Răzvan Flavius Panda
  • 21,730
  • 17
  • 111
  • 169

1 Answers1

1

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:

  1. 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();

  2. 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);
    
Community
  • 1
  • 1
Miroslav Popovic
  • 12,100
  • 2
  • 35
  • 47