【问题标题】:The INSERT statement conflicted with the FOREIGN KEY constraint in EF CoreINSERT 语句与 EF Core 中的 FOREIGN KEY 约束冲突
【发布时间】:2017-02-28 05:23:14
【问题描述】:

在不同的上下文中有很多关于这个错误的问题,到目前为止我一直无法找到一个适用于我的情况的问题。

我正在尝试与第三张桌子建立多对多关系。它基本上是一个人到经理协会。所有经理都是人,但并非所有人都是经理,而且每个人都有很多经理,每个经理都有很多人。所以在经理的表中是PersonIds。在编辑下的人员控制器中,可以选择将人员与经理关联起来。单击可用的管理器并单击保存时,出现错误:

INSERT 语句与 FOREIGN KEY 约束“FK_dbo.ManagerToEngineer_dbo.Manager_ManagerId”冲突。冲突发生在数据库“PROJECTNAME_16ce3f6a2a6c4ff0b1ce147d126984ba”、表“dbo.Manager”、列“ManagerId”中。声明已终止。

SaveChanges 方法导致此错误:

        [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);
        }

相关型号:

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; }
}

【问题讨论】:

标签: c# asp.net-core entity-framework-core


【解决方案1】:

首先,您应该重新考虑您的模型。短语:

所有经理都是人,但并非所有人都是经理

不会转化为多对多关系。一个学生有很多课程,而一个课程有很多学生是多对多的关系。您的情况更好地翻译为:每个经理都是人,暗示继承而不是对象组合。但是,出于学习目的,让我们继续您的示例。

以下代码(我稍微改变了命名,请不要将工程师和人员互换使用,因为这会增加混淆):

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"));
    }
}

在执行插入操作时,您会注意到为什么这不是一个好的设计

    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();
    }

上面的代码编译并应该运行(但我无法测试它,因为我遇到了一些 SqlLocalDb 问题)。请注意,我不需要为关联表显式创建类,只要您的 modelBuilder 具有正确的定义,Entity Framework 可以自行推断。

请记住,上面的代码只是多对多关系的一个例子,并不是一个真正好的数据库设计,但我还是把它贴出来了,而不是给你一个链接查看您的代码和我的代码之间的区别。请遵循教程here 以获得更好的理解,如果这个项目(在某些时候)不仅仅是一个学习练习,请阅读一些关于数据库设计如何转换为代码的教程(例如如何设计继承关系在 SQL 中)。

【讨论】:

  • 问题是,所有人都有很多经理,所有经理都有很多人,但所有经理都是人。
  • 哈希集有什么用?经理不是从人继承的,我以前是这样的,但我意识到我需要每个用户首​​先成为一个人,我可以让管理员让他们成为经理。
  • 也许我不太了解您要实现的目标,但这似乎是继承的教科书示例。考虑这样的层次结构: Person - 抽象类,由 Manager 和 Employer 扩展。然后,您将为每位经理保留一份员工名单,而他本人也是一个人。先设计数据库,然后再考虑 DAL。看看this
  • 我们需要用一个具体的类型来实例化我们的 ICollection,HashSet 是首选方式,因为它与您的意图相关(您不会有重复的人)而不是列表。
  • 我希望 people 下的每个用户,person 模型,并让一些人成为经理,所以他们会像列表一样进入该模型。然后我希望人们与经理联系起来。有些管理者有自己的管理者,管理者有很多人,人有很多管理者,比如我有两个,一个在我上面,一个在他上面。我下面的人比他上面的人少。我想我需要一个单独的表来关联两者,在本例中为“ManagersToEngineers”。我从这个视频中得到了这个例子:youtube.com/watch?v=g25ap6i8VH0
【解决方案2】:

您对 ManagersToEngineer 有 FK 约束,因此在对 ManagersToEngineer 进行 CUD 处理之前,请确保外部表 Engineer 和 Manager(在您的情况下为 Manager)上引用的项目有效。

更具体地说,item.Id 是否存在于您的 Manager 表中?

【讨论】:

  • item.Id 指的是 CheckBoxViewModel。
  • item.Id 指的是 CheckBoxViewModel 无关紧要。重要的是 item.Id 的值是否存在于 Managers.Select(p => p.ManagerId).ToList() 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多