简体   繁体   中英

EF6 - error when insert entity with related entites only by navigation property

I need to insert an entity WITH a related entity inside, both in a single DbSet.Add invocation.

One-to-many between Course and CourseProfesor (CourseProfesor is the entity connecting Courses and Profesors)

Entities:

public class Course
{
    public Course() { }
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    ...
    public virtual ICollection<CourseProfesor> Profesors { get; set; }
}

public class CourseProfesor
{
    public CourseProfesor() { }
    [Key]
    public int ID { get; set; }
    [Required, Index, Column(Order = 0)]
    public int CourseID { get; set; }
    [Required, Index, Column(Order = 1)]
    public int ProfesorID { get; set; }
    ...
    [ForeignKey("CourseID")]
    public virtual Course Course { get; set; }
    [ForeignKey("ProfesorID")]
    public virtual Profesor Profesor { get; set; }
}

Mappings:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Course>().HasMany(x => x.Profesors).WithRequired(x => x.Course);
    modelBuilder.Entity<CourseProfesor>().HasRequired(x => x.Course).WithMany(x => x.Profesors);
    modelBuilder.Entity<CourseProfesor>().HasRequired(x => x.Profesor).WithMany(x => x.Courses);
}

Controller:

public ActionResult Add(Course course, int profesorId = 0)
{
   if (profesor > 0)
   {
       course.Profesors = new List<CourseProfesor>();
       course.Profesors.Add(new CourseProfesor() { Course = course, CourseID = 0, ProfesorID = profesorId, From = DateTime.Now, Role = ... });
   }
   Facade.Create(course);
   return Json(new {statusText = "Course Added"});
}

Facade.Create(entity) executes a CreateCommand which will in turn invoke

DbContext.Set(entity.GetType()).Add(entity)

The exception I get:

The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property value(s) of 'Course.ID' on one end of a relationship do not match the property value(s) of 'CourseProfesor.CourseID' on the other end

how to assign CourseProfesor.CourseID if I don't know the ID of the course yet, since both are new entities?
As you can see in the controller code, I used to worked that out that by setting only the navigation property and EF would auto-populate foreign key accordingly.
This is important: This was working fine on EF5, I got that error after updating to EF6

Any clues why EF6 throws that exception while EF5 didn't? and how to solve it without having to first create the Course and then the CourseProfesor relationship entity?

A couple of things stand-out:

course.Profesors.Add(new CourseProfesor() { Course = course, CourseID = 0, ProfesorID = profesorId, From = DateTime.Now, Role = ... });

When using navigation properties I steer away from defining the FKs fields in the entities, but if you need to define them, you should avoid setting them. Use the navigation properties only. Setting FKs can be misleading because if you were to pass this Course out with it's CourseProfessors and consume it, there would be a ProfessorID set, but no Professor reference available.

Regarding your specific problem the probable issues would be the CourseID = 0 set above, and the two-way mapping between the Course and CourseProfessor.

modelBuilder.Entity<Course>().HasMany(x => x.Profesors).WithRequired(x => x.Course);
//modelBuilder.Entity<CourseProfesor>().HasRequired(x => x.Course).WithMany(x => x.Profesors);
modelBuilder.Entity<CourseProfesor>().HasRequired(x => x.Profesor).WithMany(x => x.Courses);

Try removing that redundant mapping.

Also the definition of the linking table has an ID as a PK, but isn't set up with a generation option. The two FKs are set up Order=0 and Order=1 as well, which looks odd without considering the PK?

Beyond that, I can't say I like that facade pattern. To eliminate the possibility, what happens if you go to the DB Context Courses DBSet?

context.Courses.Add(course);
context.SaveChanges(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM