Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Many to Many: Delete one side, the relationship entry BUT don't delete the other side

I want to delete an user which has many usergroups but those usergroups don't belong exclusivly to this user: other users can also be using this usergroups. And usergroups can exist even if no user references them.

I want to map the many-to-many relationship so that if a user is deleted, the relationship is automatically deleted but NOT the usergroup?

I tried Cascade.All as I thought cascades on many-to-many affect the relationship but not the other side. I thought that only Cascade.AllDeleteOrphan would do the otherside delete. Obviously I'm wrong.

It seems that I don't understand the cascade rules right. Can someone provide a clear explanation to me and maybe also a way to reach my goal?

Thanks

like image 315
David Rettenbacher Avatar asked Nov 20 '12 10:11

David Rettenbacher


People also ask

How do I delete a many-to-many relationship?

To delete a many-to-many relationship between two records, remove it from the corresponding field and save the record.

What is the difference between one to many and many to one?

The difference between One-to-many , Many-to-one and Many-to-Many is: One-to-many vs Many-to-one is a matter of perspective. Unidirectional vs Bidirectional will not affect the mapping but will make difference on how you can access your data. In Many-to-one the many side will keep reference of the one side.

Why not use Cascade delete?

Why sql server cascade delete is bad? sql server cascade delete should not cause an unexpected loss of data. If a delete requires related records to be deleted, and the user needs to know that those records are going to go away, then cascading deletes should not be used.


1 Answers

NHibernate many-to-many relation does provide what we expect, let me explain it in more details. While we need only two entities User and Group, we will need Three tables: User, Group, UserGroup (with columns UserId, GroupId)

C# entities:

public class User {
   IList<Group> Groups {get;set;}
}

public class Group{
   IList<User> Users{get;set;}
}

hbm.xml our mapping will look like this:

<class name="User" ...    
  <bag name="Groups" lazy="true" 
       table="UserGroup" cascade="none" >
    <key column="UserId" />
    <many-to-many class="Group" column="GroupId" />
  </bag>
  ...

<!-- and group vica versa -->

<class name="Group" ...
  <bag name="Users" lazy="true" 
       table="UserGroup" cascade="none" >
     <key column="GroupId" />
     <many-to-many class="User" column="UserId" />
  </bag>
    ...

This mapping with important setting cascade="none" will do expected behaviour. This mapping says that there is a PairTable UserGroup, which does not have any entity representation. So, there cannot be any cascade setting effecting this table. This table is used hiddenly behind the scene.

Pair table

When some user is deleted, then NHibernate will aslo remove all the relations from the UserGroup table (in fact this will be the first statement in the batch). This is just the relational reference constraint handling. We cannot leave any UserId in the table UserGroups, which does not have its foreign key in the User table.

The other relation end

Finally the cascade setting: Because the UserGroup table is managed without any our attention, the cascade is in this case applied to entity Group - the other relation end. So setting it to all-delete-orphan could lead to complete deletion of all cross referenced records.

Summary: cascade on a bag with many-to-many relation is meant for the other end point, not the pairing table.

like image 52
Radim Köhler Avatar answered Nov 12 '22 16:11

Radim Köhler