C# – Fluent NHibernate cascade delete not working

cfluent-nhibernate

I've got a simple phone directory app using Fluent NHibernate 1.1. In the app, a "Person" object has many "PhoneNumber" objects. I'm trying to delete a Person and I want to cascade deletes to PhoneNumbers. I set a convention of DefaultCascade.All() after reading this answer. However, attempting to delete the parent object still throws an exception–it appears that NHibernate is trying to update the child table to set the parent ID to null instead of just deleting the record:

{"could not delete collection: [Person.PhoneNumbers#473][SQL: UPDATE phone_numbers SET person_id = null WHERE person_id = @p0]"}

InnerException:

{"Cannot insert the value NULL into column 'person_id', table 'directory.dbo.phone_numbers'; column does not allow nulls. UPDATE fails.\r\nThe statement has been terminated."}

My Fluent config is:

public static ISessionFactory CreateSessionFactory() {
    return Fluently.Configure()
        .Database(MsSqlConfiguration.MsSql2008
            .ConnectionString(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["activeConnStr"]].ConnectionString))
        .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Person>()
                                        .Conventions.Add(DefaultCascade.All())
                    )
        .BuildSessionFactory();
}

The parent class is:

public class Person {
    public Person() {
        PhoneNumbers = new List<PhoneNumber>();
        EmailAddresses = new List<string>();
    }

    public virtual int Id { get; private set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual string Company { get; set; }
    public virtual IList<PhoneNumber> PhoneNumbers { get; set; }
    public virtual IList<string> EmailAddresses { get; set; }
}

The child class (PhoneNumber) is:

public class PhoneNumber {
    public virtual string Number { get; set; }
    public virtual PhoneNumberType NumberType { get; set; }
    public virtual Person Person { get; set; }
}

My code to delete a person is:

public static void DeletePerson(int id) {
    using (var session = Dalc.Instance.SessionFactory.OpenSession()) {
        using (var trans = session.BeginTransaction()) {
            session.Delete(session.Load<Person>(id));
            trans.Commit();
        }
    }
}

What am I doing wrong?

Best Answer

I'm not sure about configuring the Fluent part, but I recently had the same problem with ActiveRecord.

You need to set your association, on the Person side, as Inverse = true.

From looking at the Getting Started documentation...

I belive, you need to set this when defining your HasMany relationship in Person. It should look something like this:

public PersonMap()
{
    //<...SNIP...>
    HasMany(x => x.PhoneNumbers)
      .Inverse();
    //<...SNIP...>
}
Related Topic