Reputation: 34089
I have the code below to delete children and grandchildren from parent
MyEntities dbContext = new MyEntities();
var parent = dbContext.Parents
.Include(x => x.Childrens.Select(y => y.GrandChildrens))
.Where(x => x.ParentID == 1)
.SingleOrDefault();
// get first child
var child = parent.Childrens.First();
// remove all grand childrens from child
var count = child.GrandChildrens.Count;
for (int i = 0; i < count; i++)
{
child.GrandChildrens.Remove(child.GrandChildrens.ElementAt(0));
}
// remove child from parent
parent.Childrens.Remove(child);
// save changes
dbContext.SaveChanges();
The above code throws exception
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
after going through several article it seems like i have to mark Entity's state as deleted instead of removing entity from collection.
MyEntities dbContext = new MyEntities();
var parent = dbContext.Parents
.Include(x => x.Childrens.Select(y => y.GrandChildrens))
.Where(x => x.ParentID == 1)
.SingleOrDefault();
// get first child
var child = parent.Childrens.First();
// remove all grand childrens from child
var count = child.GrandChildrens.Count;
for (int i = 0; i < count; i++)
{
dbContext.Entry<GrandChild>(child.GrandChildrens.ElementAt(0)).State = EntityState.Deleted;
}
// remove child from parent
dbContext.Entry<Child>(child).State = EntityState.Deleted;
// save changes
dbContext.SaveChanges();
the code above works
However i have questions
1> How do i enable cascading delete so i don't have to delete GrandChildrens explicitly? I am using DB first approach.
2> If we add entity into collection and call dbContext.SaveChanges() then EF saves newly added entities, even if we DO NOT explicitly mark entity's state as Added
. Why that is not true for delete operation? Why we have to explicitly set entity's state as Deleted
Upvotes: 2
Views: 1955
Reputation: 8197
When you declare foreign key relationship between Children
and Grandchildren
you can set Delete Rule. You may do it in SQL Management Studio. Just choose Cascade. Now SQL Server will delete all related records in the child table when you delete records in the parent table.
I can only guess. What if you don't need to delete the records, but just want to break the relationship? What method would you use? The method ICollection.Remove
looks like a good candidate. So it was just a choice of authors of EF.
Upvotes: 0
Reputation: 34673
Ah man, I've been bouncing between ORMs too much... One of the remaining reasons I prefer NHibernate, was already with a response about cascade delete orphans which isn't in EF6, but is apparently available in EF Core and expected for EF7...
For EF6 to need to mark the entities as Deleted because it still lacks the concept of orphan tracking. :(
A slightly less verbose variant to
var child = parent.Childrens.First();
child.GrandChidrens.ToList().ForEach(x=>dbContext.Entity(x).State = EntityState.Deleted);
dbContext.Entity(child).State = EntityState.Deleted;
parent.Childrens.Remove(child);
You could try EF Core, though it's got plenty of other dragons...
Upvotes: 1