TheBoubou
TheBoubou

Reputation: 19903

NHibernate : update an ISet collection

See the class and mapping below. I'd like in some case update the address (at this time, it's all the time one address).

I do this :

var customer = session.Get<Customer>(customerId);
customer.Address.Clear();
customer.Address.Add(address);

address is coming from a form, the id field is not = 0 (when 0, at creation, no problem)

but when I do this :

session.Save(customer);
session.Commit(); 

I receive an exception on the commit (14 is the id of CustomerAddress) :

a different object with the same identifier value was already associated with the session: 14, of entity: CustomerAddress

What is the way to update this address ?

Thanks,

Class and Mapping

public class Customer
{
    public virtual int Id { get; set; }
    public virtual string LastName { get; set; }
    public virtual Iesi.Collections.Generic.ISet<CustomerAddress> Address { get; set; }

    public Customer()
    {
        Address = new Iesi.Collections.Generic.HashedSet<CustomerAddress>(); 
    }
}

public class CustomerAddress
{
    public virtual int Id { get; set; }
    public virtual string Street { get; set; }
    public virtual Customer Customer { get; set; }
}

public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id).GeneratedBy.Native();
        Map(x => x.LastName)
            .Length(50)
            .Not.Nullable();    
        HasMany(x => x.Address)
            .AsSet()
            .Inverse()
            .Cascade.AllDeleteOrphan()
            .Not.LazyLoad();
    }
}

public class CustomerAddressMap : ClassMap<CustomerAddress>
{
    public CustomerAddressMap()
    {
        Id(x => x.Id).GeneratedBy.Native();
        Map(x => x.Street).Length(50);
        References(x => x.Customer);
    }
}

Upvotes: 0

Views: 557

Answers (2)

acarasso
acarasso

Reputation: 146

If the address you are saving already has an id assigned to it you can simply do the following:

var customer = session.Get<Customer>(customerId);
Session.Merge(address);  // This will copy your transient entity into 
                         // ..an entity with the same id that is in the 
                         // ..first level cache.
session.SaveOrUpdate(customer);

You are getting that error because and address with an ID of 14 is already associated with your NHibernate session. So when you create the new detached transient entity and try to save it with that id NHibernate throws an error. Generally this is a good thing as it is very rare to want to do what you are doing.

A far better pattern would be to have a ViewModel for the fields of an address that are changeable by a user, and then do the following:

var address = Session.Get<Address>(addressVM.Id);
Mapper.Map(addressVM, address); // This is some type of mapper to copy properties 
                                // ..from one object to another.  I like automapper               
                                // ..for this
Session.SaveOrUpdate(address);

Upvotes: 1

Diego Mijelshon
Diego Mijelshon

Reputation: 52725

If you are updating an address, why are you clearing the collection and re-adding?

using (var tx = session.BeginTransaction())
{
    var customer = session.Get<Customer>(customerId);
    var address = customer.Address.Single(/*optional condition here*/);
    //or, if you are not updating the Customer, this might be better
    var address = session.Get<Address>(addressId);
    address.Street = updatedStreetInfo;
    tx.Commit();
}

Upvotes: 0

Related Questions