Cascade deleting with EF Core
Cascade delete always works in one direction - from principal entity to dependent entity, i.e. deleting the principal entity deletes the dependent entities. And for one-to- many relationships the one side is always the principal and the many side is the dependent.
Looks like you are confused by the fluent configuration. Note that each relationship consists of two ends. The fluent configuration allows you to start with one of the ends and relate it to the other end, or vice versa, but still you are configuring (defining) a single relationship. So
Entity<A>().HasOne(a => a.B).WithMany(b => b.As)
is the same as
Entity<B>().HasMany(b => b.As).WithOne(a => a.B);
and they both define one and the same relationship. Which one you choose doesn't matter, just use single configuration per relationship in order to avoid discrepancies.
With that being said,
model.Entity<Post>().HasOne(p => p.Blog).WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);
and
model.Entity<Blog>().HasMany(b => b.Posts).WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);
is one and the same and define single one-to-many relationship from Blog
to Post
. Since Blog
is the one side and Post
is the many side, the Blog
is the principal entity and the Post
is the dependent entity, hence deleting a Blog
will delete the related Post
s.
Reference:
- Relationships - Definition of terms
- Cascade Delete
Entity Framework (Core) - cascading delete
Actually EF Core 3.0 is the first version of EF which adds such capability via DeleteBehavior.ClientCascade option (unfortunately not yet included in the Cascade Delete section of the documentation):
For entities being tracked by the
DbContext
, dependent entities will deleted when the related principal is deleted.If the database has been created from the model using Entity Framework Migrations or the
EnsureCreated()
method, then the behavior in the database is to generate an error if a foreign key constraint is violated.
Shortly, all Client*
delete behaviors are mapped to Restrict
, i.e. enforced FK relationship in database without cascade. Client behavior apply only on entities tracked by the context, so make sure you Include
the related data before deleting (as in your sample).
To configure the option, you'd need fluent API at minimum having valid Has
+ With
in order to get to OnDelete
method, e.g.
modelBuilder.Entity<Blog>()
.HasMany(e => e.Posts)
.WithOne(e => e.Blog)
.OnDelete(DeleteBehavior.ClientCascade);
In EF Core Migration when setting Cascade Delete does it not enforce it in the database?
After looking through the project which I was trying to do this in a realised that the Dbcontext was inherited from a base class which had this code in...
private void ConfigureEntities(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);
var entityTypes = modelBuilder.Model
.GetEntityTypes()
.ToList();
// Disable cascade delete
var foreignKeys = entityTypes
.SelectMany(e => e.GetForeignKeys().Where(f => f.DeleteBehavior == DeleteBehavior.Cascade));
foreach (var foreignKey in foreignKeys)
{
foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
}
}
In the end I copied this into the Gist Project and replicated it straight away.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TestContext).Assembly);
var entityTypes = modelBuilder.Model
.GetEntityTypes()
.ToList();
var foreignKeys = entityTypes
.SelectMany(e => e.GetForeignKeys().Where(f => f.DeleteBehavior == DeleteBehavior.Cascade));
foreach (var foreignKey in foreignKeys)
{
foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
}
}
I'm not sure why this was done but plan to find out, I think it came from a previous Template that we were using.
EF Core Cascade Delete
This is what I ended up doing .. I did it in code
public async Task DeleteRound(int Id)
{
var round = _context.Rounds.Where(e => e.Id==Id).Include(e => e.Activitys).First();
_context.Rounds.Remove(round);
await _context.SaveChangesAsync();
}
I had to add the following to the Round Class:
public IList<Activity> Activitys { get; } = new List<Activity>();
No further code required. No need to populate the list as above. It seems that EF is doing it seamlessly. No need to annotate the Migration files.
Entity Framework Core Cascade Delete Error
I think the behavior is correct since when the master table deletes a record it should delete its related records in the detail table. No point in keeping it. Data will be redundant. But in case if we want to make such a scenario, though we set CascadeDelete to Restrict within the migration.cs it will not work as expected. The following article will help with understanding the behaviours.
https://learn.microsoft.com/en-us/ef/core/saving/cascade-delete
Entity Framework Core cascade delete one to many relationship
Described "problem" is not related to Entity Framework - this is restriction of MS SQL Server itself. Table with several FKs may have only one of them with cascade delete.
So, as soon as you need both FKs to have cascade - you should implement such "cleanup" in your code. Set one (or both) FKs to DeleteBehavior.Restrict
, and in your controller/service prior to removing Station
manually find and delete all related RegulatorySchedule
Related Topics
Changing the Cursor in Wpf Sometimes Works, Sometimes Doesn'T
How to Find the Fully Qualified Name of an Assembly
Creating Powerpoint Presentations Programmatically
Asynchronously Sending Emails in C#
How to Get the Available Wifi Aps and Their Signal Strength in .Net
When Is Readerwriterlockslim Better Than a Simple Lock
Register Background Task in Silverlight 8.1 App
ASP.NET MVC - Passing Parameters to the Controller
Which Is Better Between a Readonly Modifier and a Private Setter
How to Await a List of Tasks Asynchronously Using Linq
Linq to SQL Where Clause Optional Criteria
Can a Dbcontext Enforce a Filter Policy
Cookie Confusion with Formsauthentication.Setauthcookie() Method
Visual Studio 2015 Is Extremely Slow
Nsubstitute - Testing for a Specific Linq Expression