2
votes

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

2

2 Answers

1
votes

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...

0
votes
  1. 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.

  2. 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.