Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OnDelete restrict doesn't allow me delete an entity #8342

Closed
ComptonAlvaro opened this issue Apr 30, 2017 · 8 comments
Closed

OnDelete restrict doesn't allow me delete an entity #8342

ComptonAlvaro opened this issue Apr 30, 2017 · 8 comments

Comments

@ComptonAlvaro
Copy link

ComptonAlvaro commented Apr 30, 2017

I have two entities, one parent entity and one child entity. The relationship between both are this:

entity.HasOne(d => d.EntityParent)
    .WithMany(p => p.EntityCHild)
    .HasForeignKey(d => d.IDEntityParent)
    .OnDelete(DeleteBehavior.restrict)
    .HasConstraintName("FK_Name");

But when I try to delete the parent entity I get an error that says that I can't delete the parent entity because it doesn't allow to set null values. I have to configure the OnDelete if I want to delete the parent entity. If I set on cascade, then I don't have problems or I can delete OnDelete configuration and it works too.

In my database, I have configurated the foreign key in the child table that doesn't allow null value, so it is coherent the message error that I receive.

In my database, I don't have child entities, so how I could delete the parent entity? Really the strict configuartion is the correct one, because the foreign key in the child doesn't allow null values, so I guess that the correct configuration is restric, but If I set this configuration, I can't delete the parent entity when it has not childs.

This is the expected behavior? Because it is, I don't know how I can delete the parent entity, because if I execute the query directly in the database I will not get errors because it has not childs, but EF doesn't allow me because of this error.

thanks.

EDIT: I get this error:

"The association between entity types 'MyTypeParent' and 'MyTypeChild' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes."

The relationship is configurated as restrict. According to the documentation:

"The delete operation is not applied to dependent entities. The dependent entities remain unchanged."

So if the dependent entities remain unchanged, the foreign key still is the same that they had, so it shouldn't be changed to null, that seems the meaning of the error. If not, what is the difference between set null and restrict?

If I set OnDelete as setNull, I get this error:

"The association between entity types 'myEntityparent' and 'MyEntityChild' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes."

Is the same message error, so what is the difference between restrict and setNull?

Thanks.

@ajcvickers
Copy link
Member

@ComptonAlvaro Agree the documentation is confusing. We will take a look at making it better.

You should have no trouble deleting a parent entity if it has no children. If the parent entity does have children, and the FK is non-nullable, then deleting the parent will cause an error because the constraint on the children means that they cannot continue to exist without the parent. This is the same as for an FK constraint in the database. If you want the children to continue to exist without the parent, then the FK property must be nullable such that a child can exist without referencing a parent.

@ComptonAlvaro
Copy link
Author

I understand that. But in my case, if I set restrict and I get all the childs from database, if I delete the childs in the dbContext and the parent too, I get this error. It is true that the database doesn't allow null values in the relationship, but I get all the childs from database and I delete them. So why I get this error? EF should allows to delete them, and if a new child is add while I am deleting them then the error should come from database, not from EF.

Also, the message error that gives EF is not very clear, because in strict and in setNull configurations, I get the same message error. Why EF try to set to null the FK if according to documentation restrict will not change any value?

@ajcvickers
Copy link
Member

@ComptonAlvaro With regard to, " I get all the childs from database, if I delete the childs in the dbContext and the parent too, I get this error." I am not able to reproduce this. If I mark the parent and all the children as deleted, then EF will delete them all. Here is the code I used to try to reproduce what you are seeing. Maybe you can look at this and try to see what is different from your case?

public class Program
{
    public static void Main()
    {
        using (var context = new BlogContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            context.Add(new Blog { Posts = new List<Post> { new Post(), new Post(), new Post() } });
            context.SaveChanges();
        }

        using (var context = new BlogContext())
        {
            var blog = context.Blogs.Include(e => e.Posts).FirstOrDefault();

            context.RemoveRange(blog.Posts);
            context.Remove(blog);
            context.SaveChanges();
        }
    }
}

public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(
            "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>().HasOne(d => d.Blog)
            .WithMany(p => p.Posts)
            .HasForeignKey(d => d.BlogId)
            .OnDelete(DeleteBehavior.Restrict)
            .HasConstraintName("FK_Name");
    }
}

@ajcvickers
Copy link
Member

@ComptonAlvaro Agree that the documentation is confusing. At runtime, EF doesn't really treat Restrict and SetNull differently.

Note for triage: this is the enum we have, which is used directly by the OnDelete method in Code First:

/// <summary>
///     Indicates how a delete operation is applied to dependent entities in a relationship when the principal is deleted
///     or the relationship is severed.
/// </summary>
public enum DeleteBehavior
{
    /// <summary>
    ///     The delete operation is not applied to dependent entities. The dependent entities remain unchanged.
    /// </summary>
    Restrict,

    /// <summary>
    ///     The foreign key properties in dependent entities are set to null. This cascading behavior is only applied
    ///     to entities that are being tracked by the context. A corresponding cascade behavior should be setup in the
    ///     database to ensure data that is not being tracked by the context has the same action applied. If you use
    ///     EF to create the database, this cascade behavior will be setup for you.
    /// </summary>
    SetNull,

    /// <summary>
    ///     Dependent entities are also deleted. This cascading behavior is only applied
    ///     to entities that are being tracked by the context. A corresponding cascade behavior should be setup in the
    ///     database to ensure data that is not being tracked by the context has the same action applied. If you use
    ///     EF to create the database, this cascade behavior will be setup for you.
    /// </summary>
    Cascade
}

@ComptonAlvaro
Copy link
Author

Well, i found the problem. In my case I was using raw sql with the fromSql() method, and also i was doing the incluide, but in my t-sql query I didn't get the childs, so EF knows that I have not childs although I was doing the include. When I add the childs in the t-sql it works.

So it was my problem.

Thank you so much.

@ajcvickers ajcvickers self-assigned this May 6, 2017
@ajcvickers ajcvickers added this to the 2.0.0 milestone May 6, 2017
@ajcvickers
Copy link
Member

Discussed in triage to leave API unchanged but update docs to clarify that Restrict and SetNull have the same behavior for tracked entities.

@ajcvickers
Copy link
Member

Note: See other documentation issues noted in #8485

@ajcvickers
Copy link
Member

Superceeded by #8654

@ajcvickers ajcvickers removed this from the 2.0.0 milestone Jun 5, 2017
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants