11

I have two entities (Customer and CustomerRole) and would like to declare many-to-many relationship between them. I can do using the following code:

modelBuilder.Entity<CustomerRole>()
        .HasMany(cr => cr.Customers) 
        .WithMany(c => c.CustomerRoles)
        .Map(m => m.ToTable("Customer_CustomerRole_Mapping"));

But it creates the relationship (and the third mapping table) with cascade delete switched off by default. How can I tell EF to create the relationship with cascade delete switched on when using many-to-many?

Andrei M
  • 3,429
  • 4
  • 28
  • 35

1 Answers1

8

As of CTP5, there seems to be no way to directly turn on cascade deletes on Many to Many associations by Fluent API.

That said, if your intention is to make sure that you can delete the principal (e.g. a Customer record) without having to worry about the dependent record in the join table (i.e. Customer_CustomerRole_Mapping) then you don't need to turn on cascades on the database since EF Code First will take care of the cascade deletes on the client side when it comes to Many to Many associations.

For example, when you delete a Customer object, EF is smart enough to first send a delete statement to get rid of the dependent record in the join table and after that it will send another delete statement to delete the Customer record.

Update:

Due to a bug in CTP5, you need to explicitly eager/Lazy load the navigation property and have it loaded on the context when you remove the dependent. For example, consider this model:

public class User
{
 public int UserId { get; set; }
 public virtual ICollection Addresses { get; set; }
}

public class Address
{
 public int AddressID { get; set; } 
 public virtual ICollection Users { get; set; }
}

Assuming that we have a User with an address in the database, this code will throw:

using (EntityMappingContext context = new EntityMappingContext())
{
 User user = context.Users.Find(1); 
 context.Users.Remove(user);
 context.SaveChanges();
}

However, this one will perfectly work with removing the link table's record first:

using (EntityMappingContext context = new EntityMappingContext())
{
 User user = context.Users.Find(1); 
((IObjectContextAdapter)context).ObjectContext
                                .LoadProperty(user, u => u.Addresses);
 context.Users.Remove(user);
 context.SaveChanges();
}

Please note that this is just a workaround and we will be able to (hopefully) remove a principal without loading its navigation property.

Morteza Manavi
  • 33,026
  • 6
  • 100
  • 83
  • No, it seems that EF is not smart enough because I'm get the following exception: "The DELETE statement conflicted with the REFERENCE constraint "CustomerRole_Customers_Target". The conflict occurred in database "db_name_here", table "dbo.Customer_CustomerRole_Mapping", column 'CustomerId'. The statement has been terminated." – Andrei M Jan 04 '11 at 17:44
  • Yes, you are right, but it was like that in CTP4 and that seems to be changed in CTP5. See this: http://stackoverflow.com/questions/4158027/how-do-i-cascade-deletes-into-a-link-table-using-the-ef4-fluent-api/4293020#4293020. I'll investigate this issue and get back to you soon. Stay tuned! – Morteza Manavi Jan 04 '11 at 17:58
  • For some reason, I cannot reproduce the exception anymore! Can you please post your code that throws as well as your object model? – Morteza Manavi Jan 05 '11 at 15:23
  • Morteza, I've found the answer. I also asked the same question on MSDN forums. You can find it and the "answer" here - http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/3803853b-bca9-4e20-adad-2d5dd45bd3b8 – Andrei M Jan 05 '11 at 18:38
  • Ok, I can see that Zeeshan provided pretty much the same answer except that he eager load the navigation properties by Include method. So is that what that solves your problem? Meaning that it throws if you don't Include? – Morteza Manavi Jan 05 '11 at 20:00
  • I've updated the answer, now with loading the navigation property, EF becomes smart enough ;-) – Morteza Manavi Jan 06 '11 at 15:30