Entity Framework (EF) Code First Cascade Delete for One-to-Zero-or-One relationship
You will have to use the fluent API to do this.
Try adding the following to your DbContext
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(a => a.UserDetail)
.WithOptionalDependent()
.WillCascadeOnDelete(true);
}
EF Core Deleting related entities on One To One relationship
I see your One-to-One
Fluent API configuration is not written in correct way as you did not specify the dependent entity. Your Fluent API configuration should be written as follows:
modelBuilder.Entity<Article>().HasOne(a => a.MediaPlan)
.WithOne(mp => mp.Article)
.HasForeignKey<Article>(a => a.MediaPlanId)
.OnDelete(DeleteBehavior.Cascade);
Now deleting a MediaPlan
will also delete its dependent Article
as follows:
var mediaPlanToBeDeleted = await _db.MediaPlans.FirstOrDefaultAsync(x=>x.Id == id);
_db.MediaPlans.Remove(mediaPlanToBeDeleted);
await _db.SaveChangesAsync();
Now if you want the reverse behavior then you have to reverse your Fluent API configuration.
Note: Only deleting the principal entity will cascade delete the dependent entity. Vice-versa is not possible.
Cascade delete in one to one relationship
You are right, it is your many-to-many relation ship between Article
and Category
: one Article
has zero or more Categories
and every Category
may be used by zero or more Articles
.
If you delete an Article
, its Categories
can't be deleted automatically, because the Category
might be used by other Articles
, and even if it isn't used right now, entity framework doesn't know whether you want to use it tomorrow. After all, you specified that every Category
might be used by zero or more Articles
.
Similarly, if you remove a Category
, entity framework can't automatically remove the Articles
belonging to this category.
This differs from a one-to-many relationship. For example, if you have a one-to-many relationship of a Book
and its Pages
, then every Book
has zero or more Pages
and every Page
belongs to exactly one Book
.
If you remove the Book
, then entity framework knows that it should automatically remove all Pages
of the Book
, which are all Pages
with a foreign key BookId
. If Entity Framework would only remove the Book
, then we would have a bunch of Pages
with foreign key value pointing to a non-existing Book
. So in one-to-many relations, entity framework can cascade on delete.
Alas, in many-to-many this is not possible.
On the bright side, you have the advantage that you can delete the last Article
of a Category
, and keep the Category
intact. Tomorrow you can add a new Article
that uses this Category
.
So if you want to remove an article, you manually have to remove it from the 'Categories` it uses:
many-to-many following the standard naming conventions:
class Article
{
public int Id {get; set;}
// an Article belongs to zero or more Categories:
public virtual ICollection<Category> Categories {get; set;}
...
}
class Category
{
public int Id {get; set;}
// a Category is used by zero or more Articles:
public virtual ICollection<Article> Articles{get; set;}
...
}
Don't forget to declare your ICollections virtual!
class MyDbContext : DbContext
{
public class DbSet<Article> Articles {get; set;}
public class DbSet<Category> Categories {get; set;}
}
You don't have to mention the junction-table, entity framework will make it automatically for you, but you won't have to use it for joins if you want Articles
with their Categories
, or Categories
with their Articles
, just use the ICollections
Note: As Categories is not the expected plural of Category, you'll have to tell entity framework the proper table name. Out of scope of this question.
Delete an Article, but keep all Categories it belongs to alive:
using (var dbContext = new MyDbContext(...))
{
Article articleToRemove = ...
dbContext.Articles.Remove(articleToRemove);
dbContext.SaveChanges();
}
Entity framework will automatically perform the proper joins, and remove the articleToRemove from every Category. However, the Categories won't be removed.
In fact, internally the Categories table doesn't change at all. All records with Article.Id will be removed from the junction table.
Related Topics
Why Filesystemwatcher Doesn't Work in Linux Container Watching Windows Volume
Byte Array to Image Conversion
How to Tell a Lambda Function to Capture a Copy Instead of a Reference in C#
JSON.Net Throws Stackoverflowexception When Using [JSONconvert()]
.Net Core: Finally Block Not Called on Unhandled Exception on Linux
How to I Catch Ssl Exceptions in a Mono Httplistener Server
How to Inject JavaScript in Webbrowser Control
Differencebetween an Int and an Integer in Java and C#
C# VS Java Enum (For Those New to C#)
When to Use Cast() and Oftype() in Linq