I've this model
public class State
{
public State()
{
this.Promotions = new List<Promotion>();
this.Branches = new List<Branch>();
this.Stores = new List<Store>();
}
public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<Promotion> Promotions { get; set; }
public virtual ICollection<Store> Stores { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
}
public class Store
{
public Store()
{
this.Promotions = new List<Promotion>();
this.Branches = new List<Branch>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Promotion> Promotions { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
public int StateId { get; set; } // Foreign key
public virtual State State { get; set; } // Navigation Property
}
public class Branch
{
public Branch()
{
this.Promotions = new List<Promotion>();
}
public int Id { get; set; }
public string Name { get; set; }
public int StoreId { get; set; } // Foreign key
public int StateId { get; set; } // Foreign key
public virtual Store Store { get; set; } // Navigation Property
public virtual State State { get; set; } // Navigation Property
public virtual ICollection<Promotion> Promotions { get; set; }
}
public class Promotion
{
public Promotion()
{
this.Stores = new List<Store>();
this.Branches = new List<Branch>();
this.Productos = new List<Producto>();
}
public int Id { get; set; }
public string Name { get; set; }
public int StateId { get; set; }
public virtual ICollection<Store> Stores { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
public virtual ICollection<Product> Products { get; set; }
public virtual State State { get; set; }
}
And this in my context:
// State
modelBuilder.Entity<State>()
.HasMany(p => p.Promotions)
.WithRequired(e => e.State)
.WillCascadeOnDelete(false);
modelBuilder.Entity<State>()
.HasMany(s => s.Branches)
.WithRequired(e => e.State)
.WillCascadeOnDelete(false);
modelBuilder.Entity<State>()
.HasMany(e => e.Stores)
.WithRequired(e => e.State)
.WillCascadeOnDelete(true);
// Store
modelBuilder.Entity<Store>()
.HasMany(b => b.Branches)
.WithRequired(s => s.Store)
.WillCascadeOnDelete(true);
// Many to many
modelBuilder.Entity<Store>().
HasMany(p => p.Promotions).
WithMany(s => s.Stores).
Map(
m =>
{
m.MapLeftKey("StoreId");
m.MapRightKey("PromotionId");
m.ToTable("Store_Promotion");
});
modelBuilder.Entity<Promotion>().
HasMany(e => e.Products).
WithMany(p => p.Promotiones).
Map(
m =>
{
m.MapLeftKey("PromotionId");
m.MapRightKey("ProductoId");
m.ToTable("Promotion_Producto");
});
modelBuilder.Entity<Branch>().
HasMany(p => p.Promotiones).
WithMany(b => b.Branches).
Map(
m =>
{
m.MapLeftKey("BranchId");
m.MapRightKey("PromotionId");
m.ToTable("Branch_Promotion");
});
Now if I turn on more than one WillCascadeOnDelete of the State (first three in the fluent mapping) I get the error
Test method Proj.Data.Tests.UnitTest1.TestPromotion threw exception:
System.Data.SqlClient.SqlException: Introducing FOREIGN KEY constraint 'FK_dbo.Branch_dbo.Store_StoreId' on table 'Branch' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors.
I know that, and I've read from Julie Lerman's book:
Some databases (including SQL Server) don’t support multiple relationships that specify cascade delete pointing to the same table
As it happens since the many to many relationship table has cascade delete coming from both related tables.
So, my question is: The only choice here is to turn off cascade delete on parent tables and handle the deletion on relationship table manually? Isn't there any workaround from Entity Framework 5 for this?
Ok, I understood the problem. It is not to have a many to many relationship, the problem is this
State -> Promotion -> PromotionStore
State -> Branch -> BranchPromotion
State -> Store -> StorePromotion
and then Store, Branch and Store have FK to State. So if I delete a State PromotionStore can be reached by 1st and 3rd possibilities.
What I ended up doing is turning off cascade delete for State and deleting the related records manually like this:
public override void Delete(State state)
{
DbContext.Entry(state).Collection(x => x.Promotions).Load();
DbContext.Entry(state).Collection(x => x.Stores).Load();
DbContext.Entry(state).Collection(x => x.Branches).Load();
var associatedPromotions = state.Promotions.Where(p => p.StateId == state.Id);
associatedPromotions.ToList().ForEach(r => DbContext.Set<Promotion>().Remove(r));
var associatedStores = state.Stores.Where(e => e.StateId == state.Id);
associatedStores.ToList().ForEach(e => DbContext.Set<Store>().Remove(e));
var associatedBranches = state.Branches.Where(s => s.StateId == state.Id);
associatedBranches.ToList().ForEach(s => DbContext.Set<Branch>().Remove(s));
base.Delete(state);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With