简体   繁体   中英

The INSERT statement conflicted with the FOREIGN KEY constraint in EF Core

There are numerous questions in varying contexts regarding this error and so far I've been unable to find one that applies to my situation.

I have a many to many relationship I'm trying to establish with a 3rd table. It's basically a person to manager association. All managers are people but not all people are managers and also, every person has many managers and every manager has many people. So in the manager's table are PersonIds. In the people controller under edit is the option to associate people with managers. When clicking the available managers and clicking save, I get the error:

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.ManagerToEngineer_dbo.Manager_ManagerId". The conflict occurred in database "PROJECTNAME_16ce3f6a2a6c4ff0b1ce147d126984ba", table "dbo.Manager", column 'ManagerId'. The statement has been terminated.

The SaveChanges method results in this error:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(PersonViewModel person)
        {
            if (ModelState.IsValid)
            {
                //var MyPerson = db.people.Find(person.PersonId);
                //MyPerson.FirstName = person.FirstName;
                //MyPerson.LastName = person.LastName;
                foreach (var item in db.ManagersToEngineers)
                {
                    if (item.EngineerId == person.PersonId)
                    {
                        db.Entry(item).State = EntityState.Deleted;
                    }
                }

                foreach (var item in person.EngineerManagers)
                {
                    if (item.Checked)
                    {
                        db.ManagersToEngineers.Add(new ManagerToEngineer() { EngineerId = person.PersonId, ManagerId = item.Id });
                    }
                }
                //db.Entry(person).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(person);
        }

Relevant models:

public class ManagerToEngineer
    {
        [Key]
        public int ManagerToEngineerId { get; set; }

        [Required]
        [ForeignKey("engineer")]
        public int EngineerId { get; set; }

        [Required]
        [ForeignKey("manager")]
        public int ManagerId { get; set; }

        public virtual Person engineer { get; set; }
        public virtual Manager manager { get; set; }

    }

public class Manager
{
    [Key]
    public int ManagerId { get; set; }

    [Required]
    [ForeignKey("person")]
    public int EngineerId { get; set; }

    public virtual Person person { get; set; }
    public ICollection<ManagerToEngineer> ManagersToEngineers { get; set; }
}

public class PersonViewModel
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    [Display(Name = "Managers")]
    public List<CheckBoxViewModel> EngineerManagers { get; set; }
}

public class CheckBoxViewModel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public bool Checked { get; set; }
}

You have a FK constraint on ManagersToEngineer so before CUDing anything on ManagersToEngineer, make sure the item referred on foreign tables Engineer and Manager (in your case, Manager) is valid.

To be more specific, does item.Id exist in your Manager table?

First, you should reconsider your models. The phrase:

All managers are people but not all people are managers

does not translate into a many-to-many relationship. A student has many courses and a course has many students is a many-to-many relationship. Your situation translated better as: every manager is a person which hints at inheritance rather than object composition. However, for learning purposes let's go ahead with your example.

The following code (I've changed naming a little bit, please don't use Engineer and Person interchangeably because it adds confusion):

public class Person
{
    public Person()
    {
        Managers = new HashSet<Manager>();
    }

    [Key]
    public int PersonId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Manager> Managers { get; set; }
}

public class Manager
{
    public Manager()
    {
        Persons = new HashSet<Person>();
    }

    [Key]
    public int ManagerId { get; set; }

    public virtual ICollection<Person> Persons { get; set; }
}

public class CompanyContext : DbContext
{
    public DbSet<Person> Persons { get; set; }

    public DbSet<Manager> Managers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
           .HasMany(p => p.Managers).WithMany(m => m.Persons)
           .Map(t => t.MapLeftKey("PersonID")
               .MapRightKey("ManagerID")
               .ToTable("PersonToManager"));
    }
}

You will notice why this is not a good design when performing an insertion:

    static void Main(string[] args)
    {
        using (var db = new CompanyContext())
        {
            // add a person
            var person = new Person() { Name = "Joe" };
            db.Persons.Add(person);

            // "make" him manager
            var manager = new Manager();
            manager.Persons.Add(person);
            db.Managers.Add(manager);

            db.SaveChanges();
        }

        Console.ReadKey();
    }

The above code compiles and should run (but I could not test it because I'm having some SqlLocalDb issues). Notice that I don't need to explicitly create a class for the association tables, Entity Framework can deduce that by itself provided that your modelBuilder has the correct definition.

Please remember that the above code is only an example of a many-to-many relationship and not an actually good database design , but I've posted it anyway instead of just giving you a link to see the difference between your code and mine. Please follow the tutorial here for a better understanding and if this is a project meant to (at some point) be more than a learning exercise please read a few tutorials on how database design translates to code (eg how to design an inheritance relationship in SQL).

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