views:

49

answers:

1

I'm getting the "Save unsaved transient entities" error in NHibernate. I have an aggregate root, neighborhood that contains addresses and person, here's some quick pseudo code to explain the relationship:

public class Neighborhood {
   public virtual int Id { get; set; }
   public virtual IList<Address> Addresses { get; set; }
}

public class Address {
   public virtual int Id { get; set; }
   public virtual string Address { get; set; }
   public virtual Person Person { get; set; } //Assume only one person per address
}

public class Person {
   public virtual int Id { get; set; }
   public virtual string Name { get; set; }
}

In my Neighborhood map I have:

   mapping.HasMany(x => x.Addresses)
        .Inverse()
        .KeyColumn("NeighborhoodFk")
        .Cascade.All()
        .AsBag();

In my code I will often want to create a and associate an Address and Person at the same time:

var address = new Address();
var person = new Person();

var address.Person = person;

var neighborhood = neighborhoodRepository.Get(id);

neighborhood.Add(address);

neighborhoodRepository.DbContext.BeginTransaction();
neighborhoodRepository.SaveOrUpdate(neighborhood);
neighborhoodRepository.DbContext.CommitTransation();

I will get the "unsaved transient entities" error on the Person entity because it is attached to the transient entity Address.

The only way I can see around this is to save the address first, make another call to the database to update neighborhood after the update, search for the address I just added, attach the person and then save again.

Is there something I'm missing to make this easier? This seems like a common use case and I don't want to be making a bunch of roundtrips to the database.

+5  A: 

Make sure you're setting the "Cascade" attribute of your mapping from Address to Person to be "save-update" or "all". You have the cascade from Neighborhood to Address, but you didn't state that this lower cascade was present. If it isn't, you're getting this error not because a Person is attached to a transient Address, but because the Address references a transient Person.

If this cascade cannot be made for whatever reason, save the Person first, then save the Neighborhood, which will cascade to the Address, and the ORM will find the referenced Person in its session and set up the reference. This MAY result in some extra "round trips" depending on if you're letting NH or the DB generate autonumber columns. NHibernate is tricky in that it will make DB calls when it's good and ready, and that may be after the entire object graph is in the NH session, or just the person. Either way, it will make an Insert call into the DB for each object being persisted, so it will make multiple "roundtrips" no matter what the code to add the items to the session looks like.

KeithS
I missed the second Cascade All, thanks!
chum of chance