1
votes

A customer can have several contact. The code below is working but... the contacts for this customer are deleted first and after inserted again. Is not possible to avoid this delete and just insert the new one ?

<class name="Customer" table="Customer">
    <id name="Id">
        <generator class="native" />
    </id>
    <property name="LastName" not-null="true" />

    <bag name="Contacts" cascade="all-delete-orphan" table="CustomerContact">
        <key column="Customer" not-null="true" />
        <many-to-many class="Contact"/>
    </bag>l
</class>

<class name="Contact" table="Contact">
    <id name="Id">
      <generator class="native" />
    </id>
    <property name="LastName" not-null="true" />

    <many-to-one name="Customer" column="Customer" not-null="true" />
</class>

public virtual void AddContact(Contact contact)
{
    Contacts.Add(contact);
    contact.Customer = this;
}

When I do this code twice, to add 2 contacts :

Contact contact = new Contact() { LastName = "MyLastName" };
Customer customer = session.Get(customerId);
customer.AddContact(contact);
session.Update(customer);

enter image description here

2
You don't need to call Update(customer) after changing it. It is in the session, it gets automatically updated. - Stefan Steinegger
How is the property Contacts implemented? - Stefan Steinegger

2 Answers

2
votes

You are using a bag for your collection, a bag can contain duplicates, does not maintain order and there is no way to identify an individual entry in the bag distinctly with SQL.

That is why NH removes and inserts all assigned entities. Use a set if it suits your requirements instead.

1
votes

This typically happens when NH lost the persistence information about the collection. It assumes that you changed the whole collection. To update the database efficiently, it removes all items in one query (delete ... where customer = 5) and inserts the new items.

You probably don't return the collection provided from NH.

Typical mistake:

  IList<Contact> Contacts
  {
    get { return contacts; }
    // wrong: creates a new List and replaces the NH persistent collection
    set { contacts = value.ToList(); }
  }

By the way, you should make the collection inverse, since it is a redundancy to the contact.Customer relation:

<bag name="Contacts" cascade="all-delete-orphan" table="CustomerContact" inverse="true">
    <key column="Customer" not-null="true" />
    <many-to-many class="Contact"/>
</bag>