3

I have a Parent entity with a 0-to-Many relationship to a Child entity. When I delete a parent I want it to automatically cascade delete all the attached children. Attempting to do so gives the following 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.

I do not understand the message talking about setting a null reference. Because of the cascade delete the children will be removed so there is no need to set any children to have null references.

My two simple entities are defined as...

public class Parent
{
    [Key]
    public int Id { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}

public class Child
{
    [Key]
    public int Id { get; set; }
    public int ParentId { get; set; }
    public virtual Parent Parent { get; set; }
}

With the following mapping...

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Child>()
        .HasRequired(x => x.Parent)
        .WithMany(x => x.Children)
        .HasForeignKey(x => x.ParentId)
        .WillCascadeOnDelete(true);
}

Looking at the generated database, it does indeed mark the foreign key relationship as cascade on delete. So the database schema looks fine. The actual code that throws the error...

Parent p = context.Parents.Find(id);
context.Entry<Parent>(p).State = System.Data.Entity.EntityState.Deleted;
context.SaveChanges();

Any ideas?

Phil Wright
  • 22,580
  • 14
  • 83
  • 137

2 Answers2

1

You code matches this well so I think you configured it correctly: https://msdn.microsoft.com/en-us/data/jj591620.aspx#CascadeDelete

I don't know why this doesn't work, cascade has always worked for me so far. I suspect some configuration. I always disable lazy loading, proxy generation and validation so that could be some this to look at.

Here are some things to try:

1) Can you delete the item manually from the database and does the cascade work then?

2) Is this a sql error or an "app" error? I suspect it's an app error an that EF validation is somehow triggering. If it's from the db the exception should and SqlException. I usually check with Sql Profiler if the command get sent too.

3) If it's an app error try disabling EF's validation and see what happens.

ctx.Configuration.ValidateOnSaveEnabled = false;  

4) When you use find does that load the children (might do if it's found in the local context) or does it have lazy loading enabled. Setting the state is recursive if I remember correctly and that could possibly mess up some things. You can check in the changetracker how many entities that are marked for deletion.

Mikael Eliasson
  • 5,157
  • 23
  • 27
1

Your error is being generated by Entity Framework, not by your database.

The problem is that you're using context.Entry<Parent>(p).State = EntityState.Deleted instead of context.Parents.Remove(p). The main difference is that calling Remove on the parent handles setting the entity state to deleted for any children with a required relationship that are loaded into the context. State = EntityState.Deleted does not.

In your case, you probably have some related Child entities loaded into the context and EF is complaining about the orphaned children. If you didn't have any children loaded, the DELETE statement would be sent to the database, and the database would handle the cascade delete normally.

Using DbSet.Remove would be preferable.

See this for more details:

Delete parent with children in one to many relationship

Community
  • 1
  • 1
jjj
  • 4,822
  • 1
  • 16
  • 39