2

How do you make EF not allow deletion of a related entity? eg:

public class Enrollment 
{
    public int EnrollmentId { get; set; }
    public virtual ICollection<Course> courses { get; set; }
}

public class Course 
{
    public int CourseId { get; set; }
    public string Name { get; set; }
}

When I create a Course A and B, and then I create an Enrollment and add those courses to it, I need it to not allow me to delete Courses A or B. When I run it through my MVC controller this has no problem:

Course course = db.Courses.Find(id);
db.Courses.Remove(course);
db.SaveChanges();

I'm not even sure exactly what to search for. I think it's enforcing or enabling a many to many referential constraint? But I don't seem to find anything. Am I supposed to not expect it to make that constraint automatically? I figured I could always add the following line to the Delete controller:

if(db.Enrollments.Any(e => e.Courses.Any(c => c.CourseId == id)))
{ //error }

Also, trying the following fluentAPI wasn't working (among many variations):

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Enrollment>()
               .HasMany<Course>(e => e.Courses)
               .WithRequired()
               .WillCascadeOnDelete(false);
        modelBuilder.Entity<Course>()
               .HasMany(e => e.Enrollments);
        base.OnModelCreating(modelBuilder);
    }
Evan Morrison
  • 652
  • 6
  • 18
  • 1
    Have a look into cascade deletes, possibly around `.WillCascadeOnDelete(false);` in `OnModelCreating`. Your question is the opposite of this one: http://stackoverflow.com/q/9752287/563532 - So you might have some luck there – Rob Nov 06 '15 at 04:02
  • Well, after trying all kinds of combinations, now I can't get update-database to succeed :( I figured `modelBuilder.Entity().HasRequired(e => e.Courses).WithOptional().WillCascadeOnDelete(false);` but doesn't seem so. – Evan Morrison Nov 06 '15 at 06:36
  • I do think modelBuilder.Entity() .HasMany(e => e.Enrollments); overrides your modelBuilder.Entity() .HasMany(e => e.Courses) .WithRequired() .WillCascadeOnDelete(false); because they both configure the same relationship. delete the second line, and it should work. Oh, and insert the inverse navigation property. – DevilSuichiro Nov 06 '15 at 08:36
  • Hmm.. I get error: `Error Number:547,State:0,Class:16 The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Courses_dbo.Enrollments_Enrollment_EnrollmentId". The conflict occurred in database "test", table "dbo.Enrollments", column 'EnrollmentId'.` modelBuilder is: http://i.imgur.com/XgwCzA2.png and models are: http://i.imgur.com/FpM6siA.png – Evan Morrison Nov 06 '15 at 21:06

1 Answers1

2

How do you make EF not allow deletion of a related entity?

You want to prevent deleting things that is in used, right? Is course and enrollments a many to many relationship? Many to many will not cascade on delete by default. Try to change to this.

public class Enrollment 
{
    public int EnrollmentId { get; set; }
    public virtual ICollection<Course> Courses { get; set; }
}

public class Course 
{
    public int CourseId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Enrollment> Enrollments { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //Need this to remove the cascade convention.
    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}
Ppp
  • 1,015
  • 9
  • 14
  • I thought it would prevent deletion by default as well. My actual models with all properties follow what you say and it doesn't work though: http://i.imgur.com/FpM6siA.png currently I'm manually checking before course deletion if any enrollments use the course and if so redirecting. – Evan Morrison Nov 06 '15 at 21:02
  • Sorry, I remembered wrongly, the convention is they will cascade delete. Add `modelBuilder.Conventions.Remove();` to remove the convention. But this will remove cascade delete from all many to many relationship. Include this namespace for the convention. `using System.Data.Entity.ModelConfiguration.Conventions;` – Ppp Nov 09 '15 at 02:04