Setting up Fluent NHibernate one-to-many with cascading deletes using the automapper

4k views Asked by At

Extreme newbie question. I have my database (SQL Server) set up to cascade deletes for my relationships so if you delete a parent entity all the children are deleted as well (ON DELETE CASCADE). I want this to be reflected in my automapped Fluent NHibernate setup. However, when I try to delete a child entity NHibernate is instead attempting to set the relationship key to NULL.

The database is super-simple: (-- for "one", -< for "many")

User ---< UserCode >--- Code >--- CodeGroup

When I delete a CodeGroup, the deletes should cascade down to Code and UserCode. When I delete a Code, it should just cascade to UserCode but leave CodeGroup untouched.

My entities (properties removed for clarity):

public class User {
    public virtual IList<Code> FoundCodes { get; private set; }
}
public class Code {
    public virtual IList<User> UsersWithCode { get; private set; }
    public virtual CodeGroup CodeGroup { get; set; }
}
public class CodeGroup {
    public virtual IList<Code> Codes { get; private set; }
}

Here's how the SessionFactory looks:

var _sessionFactory =
    Fluently.Configure()
    .Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.ConnectionString(c => c.FromConnectionStringWithKey("db")).ShowSql())
    .Cache(csb => csb.UseQueryCache())
    .Mappings(m => 
      m.AutoMappings.Add(
       AutoMap.AssemblyOf<Code>(new AutomappingConfiguration())
       .Override<User>(map => map.HasManyToMany(u => u.FoundCodes).Table("UserCode"))
       .Override<Code>(map => map.HasManyToMany(c => c.UsersWithCode).Inverse().Table("UserCode"))
       .Conventions.Add(new CustomForeignKeyConvention())))
    .BuildSessionFactory())

But when I do this:

using (var tx = _db.BeginTransaction())
{
    var codeGroup = _db.Load<CodeGroup>(id);
    _db.Delete(codeGroup);
    tx.Commit();
}

I get this:

could not delete collection: [MidnightRoseRace.Data.Entities.CodeGroup.Codes#8]
    [SQL: UPDATE [Code] SET CodeGroupId = null WHERE CodeGroupId = @p0]
Cannot insert the value NULL into column 'CodeGroupId', table 'MyNamespace.dbo.Code'; 
    column does not allow nulls. UPDATE fails.
The statement has been terminated.

All it has to do is delete, but instead it's trying to set a non-nullable foreign key to null. What's going on?

2

There are 2 answers

6
NOtherDev On BEST ANSWER

Deletes do not cascade by default in NHibernate. Set cascading on codeGroup.Codes relationship like this:

AutoMap.AssemblyOf<Code>(new AutomappingConfiguration())
    // existing overrides
    .Override<CodeGroup>(
        map => map.HasMany(c => c.Codes).Cascade.AllDeleteOrphan().Inverse())

And similarly for other relations that you need to be influenced.

Edited by OP: Just needed that ".Inverse()" at the end. Related to this question: key-many-to-one and key-property association: nhibernate won't DELETE items from set

0
Tim Scott On

You might be hitting this issue. Unless you're running 3.2.0Beta2 or later, if you want to cascade deletes you must either:

  1. make the child's FK nullable; or
  2. create a inverse relationship (that is, the child must have a mapped reference to the parent).

As you can see from the ticket this has been longstanding (and much upvoted) issue that has very recently been fixed.