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

2

1

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?

Aforethought answered 25/10, 2011 at 17:31 Comment(0)
S
2

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

Stylobate answered 25/10, 2011 at 17:46 Comment(6)
AllDeleteOrphan() isn't a member of Cascade -- perhaps you mean "All()" ?Aforethought
You're right. AllDeleteOrphan is for one-to-many only, All will go here.Stylobate
Nope, this isn't working -- An association from the table CodeGroup refers to an unmapped class: System.Collection.Generic.IList``1[[MyNamespace.Code, ...]]Aforethought
OK, this IS one-to-many, so it was correct before, but with different relation mapping. See corrected answer. Sorry for mess.Stylobate
Same error. Hey, is there any significance to the message "could not delete collection" ? That seems ominous -- it shouldn't be trying to delete a collection, just an entity.Aforethought
I've got it: need to add .Inverse() to the end of that AllDeleteOrphan() call. See #1542160 .Aforethought
P
1

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.

Perceive answered 26/10, 2011 at 1:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.