views:

535

answers:

2

I have a many to many relationship between a Team and an Employee entity.

I mapped them as following:

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id).Column("EmployeeID");

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // relationship mapping
        HasManyToMany(m => m.Teams).Table("EmployeeTeam")
            .Inverse()
            .Cascade.All()
            .AsSet()
            .LazyLoad()
            .ParentKeyColumn("EmployeeID")
            .ChildKeyColumn("TeamID");

        HasMany(p => p.LoanedItems).Cascade.SaveUpdate().KeyColumn("EmployeeId");
    }
}

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id).Column("TeamID");

        // column mapping
        Map(p => p.Name);

        // relationship mapping
        HasManyToMany(m => m.Employees)
            .Table("EmployeeTeam")
            .LazyLoad()
            .Cascade.All()
            .AsSet()
            .ParentKeyColumn("TeamID")
            .ChildKeyColumn("EmployeeID");
    }
}

Then I created 3 Teams and 2 Employees:

TeamID  EmployeeID
1       1
1       2
2       2
3       1

The Employee1 has also 2 LoanedItems(Books, Magazines). Employee2 has no LoanedItems.

Now I want to delete Employee1, who is in Team1 and Team3. In Team 1 is also Employee2. So when I delete Employee1, I assume that Employee1 is deleted and also Team3, because I also assume that an Team can only exist when it has an Employe and vice versa. So Team1 may not be deleted, because it has Employee2 and can still exists.

I used the following code lines with a new Session:

var loadedEmployee = session.Get<Employee>(1);
session.Delete(loadedEmployee);
transaction.Commit();

But what happens? -> NHibernate deletes all Teams and all Employees! -> NHibernate updated my LoanedItem table correctly by setting the FK EmployeeID to NULL.

What is wrong there?

A: 

Hi! Because of the Cascade.All on the HasManyToMany mapping.

Use Cascade.SaveAndUpdate instead, if you wish to avoid the delete cascade action.

cws
When I set both ends to SaveAndUpdate the following error occurs: {"The DELETE statement conflicted with the REFERENCE constraint \"FKDA36D134BC587C57\". The conflict occurred in database \"Ariha\", table \"dbo.EmployeeTeam\", column 'EmployeeID'.\r\nThe statement has been terminated."}
Rookian
that's because Employee is inverse. Which make the other end of the relationship responsible for the link. So when you try to delete Employee NH will try to insert null into EmployeeTeam and that's why {"The DELETE statement conflicted with the REFERENCE constraint \"FKDA36D134BC587C57\"...So give it a try without inverse on Employee.Or you will have to delete the link from the other end of the relationship as well. Like TeamMap.Employees.Delete(employee) Cheers
cws
+1  A: 

I have answered a similar question here: http://stackoverflow.com/questions/1695063/what-is-the-correct-way-to-define-many-to-many-relationships-in-nhibernate-to-all/

Reading the question and my answer maybe will help you understand what is going on with your many-to-many association.

tolism7
so If I get you right, it is recommended to split a many to many association into a many to one / one to many relationship, right?
Rookian
Well, as far as I've read it's always a good practice to split a many-to-many association to 2 one-to-many associations with the X table. I cannot say that it is recommended though. When it comes to handling save and delete operations on a many-to-many associations with cascades, I've found that spliting the association just gives more flexibility and control on what you can do but it adds more configuration. Maybe someone out there knows how to configure with NHibernate a many-to-many association and provide all the flexibility that one wants with save and delete operations through cascading.
tolism7
I ask myself, why NH does not create an internal relationship entity for a many to many relation ... so finally you can say that you have to split your many to many assoication into 2 one to many assocations as you mentioned, because you can only give the responsiblity to one site of your association.
Rookian