在我的种子数据/数据库模型中导致此外键冲突的原因是什么?

时间:2015-11-05 22:14:15

标签: c# sql-server database entity-framework database-design

我已经尝试了几个小时,但我无法将我的种子数据用于我的实体框架数据库。

我一直收到以下错误:

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Appointment_dbo.Employee_EmployeeID". The conflict occurred in database "BezoekersDBContext", table "dbo.Employee", column 'ID'.

堆栈跟踪的更大部分:

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Appointment_dbo.Employee_EmployeeID". The conflict occurred in database "BezoekersDBContext", table "dbo.Employee", column 'ID'.

另一个烦恼:

每次我在程序包管理器控制台中运行update-database时,它都会不断添加种子数据的第一部分Employee表数据。这就是为什么employee表现在有大约6个条目,但Employee Table的主键是7,8,9,10,11和12.这可能/可能是问题的一部分。我想删除数据库以重置这些密钥并使用update-database重新添加它,但是当我尝试删除数据库时,我收到一条错误消息,说明数据库正在使用中。

我在这里结束了我的智慧。我将删除我的数据库图表,模型,Dbcontext,SQL服务器表数据和种子数据。我希望你们能帮助我。 如果您发现我的模型有任何错误,请告诉我!帮助一个同事程序员!

我已经阅读this SO question(这是一个已经可以回答的问题)并且用户说我的外键应该可以为空。我的所有人都无法自负,他们都是必需的。另一位用户说了一些关于制作我的导航属性virtual的信息,但是我已经删除了这个以消除this weird error导致我的网络API无法从数据库中检索数据返回给调用者:

  

如果您有导航属性,则将它们设为非虚拟。映射仍然有效,但它会阻止创建无法序列化的动态代理实体。   没有延迟加载在WebApi中很好,因为您没有持久连接并且无论如何都运行了.ToList()。

图表(使用EF Power Tools创建):

Diagram of my database

模型

访问者

public class Visitor
{
    [Key]
    public int ID
    { get; set; }

    [Required]
    public string FirstName
    { get; set; }

    [Required]
    public string LastName
    { get; set; }

  //[Key] I have to configure this later
    [Required]
    [EmailAddress]
    public string Email
    { get; set; }

    public string Company
    { get; set; }

    public string Image
    { get; set; }

    public string PhoneNumber
    { get; set; }

    public ICollection<Appointment> Appointments
    { get; set; }
}

预约

public class Appointment
{
    [Key]
    public int ID
    { get; set; }

    [Required]
    public int EmployeeID
    { get; set; }

    [Required]
    public string Location
    { get; set; }

    public string Comment
    { get; set; }

    [Required]
    public DateTime Date
    { get; set; }


    public ICollection<Visitor> Visitors
    { get; set; }

    public ICollection<Collector> Collectors
    { get; set; }

    [ForeignKey("EmployeeID")]
    public Employee Employee
    { get; set; }

}

集电极

public class Collector
{
    [Key]
    public int ID
    { get; set; }

    [Required]
    public int AppointmentID
    { get; set; }

    [Required]
    public int EmployeeID
    { get; set; }

    [Required]
    public int Preference
    { get; set; }

    [ForeignKey("EmployeeID")]
    public Employee Employee
    { get; set; }

    [ForeignKey("AppointmentID")]
    public Appointment Appointment
    { get; set; }
}

员工

public class Employee
{
    [Key]
    public int ID
    { get; set; }

    //[Key] I have to configure this later
    [Required]
    public int SAP_ID
    { get; set; }

    [Required]
    public string FirstName
    { get; set; }

    [Required]
    public string LastName
    { get; set; }

    [Required]
    [EmailAddress]
    public string Email
    { get; set; }

    public string Image
    { get; set; }

    [Required]
    public string PhoneNumber
    { get; set; }

    public ICollection<Appointment> Appointments
    { get; set; }

}

的DbContext

public class BezoekersDBContext : DbContext
{

    public BezoekersDBContext() : base("BezoekersDBContext")
    {
    }
    public DbSet<Appointment> Appointments
    { get; set; }
    public DbSet<Employee> Employees
    { get; set; }
    public DbSet<Collector> Collectors
    { get; set; }
    public DbSet<Visitor> Visitors
    { get; set; }


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<Collector>().HasRequired(d => d.Employee).WithMany().WillCascadeOnDelete(false);
    }

WillCascadeOnDelete已启用,因为CollectorEmployeeEmployee 并非总是Collector。 (收藏家是指接待访客并将他带到预约地点的人。他也是一名雇员)。 没有启用此选项给了我关于Cascade循环和路径的错误,我发现很多SO答案告诉我使用此选项来解决该问题。

表格的SQL代码

访问者

CREATE TABLE [dbo].[Visitor] (
    [ID]          INT            IDENTITY (1, 1) NOT NULL,
    [FirstName]   NVARCHAR (MAX) NOT NULL,
    [LastName]    NVARCHAR (MAX) NOT NULL,
    [Email]       NVARCHAR (128) NOT NULL,
    [Company]     NVARCHAR (MAX) NULL,
    [Image]       NVARCHAR (MAX) NULL,
    [PhoneNumber] NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_dbo.Visitor] PRIMARY KEY CLUSTERED ([ID] ASC)
);

预约

CREATE TABLE [dbo].[Appointment] (
    [ID]         INT            IDENTITY (1, 1) NOT NULL,
    [EmployeeID] INT            NOT NULL,
    [Location]   NVARCHAR (MAX) NOT NULL,
    [Comment]    NVARCHAR (MAX) NULL,
    [Date]       DATETIME       NOT NULL,
    CONSTRAINT [PK_dbo.Appointment] PRIMARY KEY CLUSTERED ([ID] ASC),
    CONSTRAINT [FK_dbo.Appointment_dbo.Employee_EmployeeID] FOREIGN KEY ([EmployeeID]) REFERENCES [dbo].[Employee] ([ID]) ON DELETE CASCADE
);

集电极

CREATE TABLE [dbo].[Collector] (
    [ID]            INT IDENTITY (1, 1) NOT NULL,
    [AppointmentID] INT NOT NULL,
    [EmployeeID]    INT NOT NULL,
    [Preference]    INT NOT NULL,
    CONSTRAINT [PK_dbo.Collector] PRIMARY KEY CLUSTERED ([ID] ASC),
    CONSTRAINT [FK_dbo.Collector_dbo.Employee_EmployeeID] FOREIGN KEY ([EmployeeID]) REFERENCES [dbo].[Employee] ([ID]),
    CONSTRAINT [FK_dbo.Collector_dbo.Appointment_AppointmentID] FOREIGN KEY ([AppointmentID]) REFERENCES [dbo].[Appointment] ([ID]) ON DELETE CASCADE
);


GO
CREATE NONCLUSTERED INDEX [IX_AppointmentID]
    ON [dbo].[Collector]([AppointmentID] ASC);


GO
CREATE NONCLUSTERED INDEX [IX_EmployeeID]
    ON [dbo].[Collector]([EmployeeID] ASC);

员工

CREATE TABLE [dbo].[Employee] (
    [ID]          INT            IDENTITY (1, 1) NOT NULL,
    [SAP_ID]      INT            NOT NULL,
    [FirstName]   NVARCHAR (MAX) NOT NULL,
    [LastName]    NVARCHAR (MAX) NOT NULL,
    [Email]       NVARCHAR (MAX) NOT NULL,
    [Image]       NVARCHAR (MAX) NULL,
    [PhoneNumber] NVARCHAR (MAX) NOT NULL,
    CONSTRAINT [PK_dbo.Employee] PRIMARY KEY CLUSTERED ([ID] ASC)
);

种子数据

现在,我的Employee表中有行,其ID从7开始,因为我已经删除了数据库并使用了Update-Database。我已经更改了即将发布的代码示例以匹配这些主键。

如果某人有比使用.Single(x => x.ID == NUMBERHERE);更好的解决方案,因为如果我收到更多错误并增加自动增量,我可能需要更改它,请告诉我!我搜索了很多解决方案,但我找不到任何东西!

    internal sealed class Configuration : DbMigrationsConfiguration<BezoekersRegistratie_BackEnd2.DAL.BezoekersDBContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(BezoekersDBContext context)
    {
        var employees = new List<Employee>
        {
            new Employee { FirstName="Jan", LastName="Scholten", Email="JanScholten2948@outlook.com", Image="http://lorempixel.com/400/400", PhoneNumber="0675876573", SAP_ID= 20149203, Appointments = new List<Appointment>()},
            new Employee { FirstName="Bart", LastName="de Vries", Email="BartDeVries23@outlook.com", Image="http://lorempixel.com/400/400", PhoneNumber="0655544422", SAP_ID=20148394, Appointments = new List<Appointment>()},
            new Employee { FirstName="Denke", LastName="Eekhoorn", Email="DenkeEekhoorn39@gmail.com", Image="http://lorempixel.com/400/400", PhoneNumber="0674738383", SAP_ID=2039388, Appointments = new List<Appointment>() }
        };

        employees.ForEach(e => context.Employees.AddOrUpdate(p => p.ID, e));
        context.SaveChanges();

        var appointments = new List<Appointment>
        {
            new Appointment { Employee = employees.FirstOrDefault(e => e.ID == 7),Location = "Apeldoorn", Comment="Rolstoeltoegang is nodig!", Date = new DateTime(2015, 11, 12, 13, 14, 0), Visitors = new List<Visitor>(), Collectors = new List<Collector>() },
            new Appointment { Employee = employees.FirstOrDefault(e => e.ID == 8),Location = "Zwolle", Comment="Kan laat zijn.", Date = new DateTime(2016,2,11,14,12,0), Visitors = new List<Visitor>(), Collectors = new List<Collector>() },
            new Appointment { Employee = employees.FirstOrDefault(e => e.ID == 9),Location="Amsterdam", Comment="Geen speciale opmerking", Date = new DateTime(2015,12,18,15,15,0), Visitors = new List<Visitor>(), Collectors = new List<Collector>() }
        };

        appointments.ForEach(a => context.Appointments.AddOrUpdate(p => p.ID, a));
        context.SaveChanges();

        employees[0].Appointments.Add(appointments[0]);
        employees[1].Appointments.Add(appointments[1]);
        employees[2].Appointments.Add(appointments[2]);

        context.SaveChanges();

        var visitors = new List<Visitor>
        {
            new Visitor { FirstName="Sander", LastName="ten Brinke", Email="sander.ten.brinke@xs4all.nl", Company="BelastingDienst", Image = "http://lorempixel.com/400/400", PhoneNumber="0620556193", Appointments = new List<Appointment>()  },
            new Visitor { FirstName="Reinold", LastName="Boeve", Email= "reinold.boeve@gmail.com", Company="Harvy", Image= "http://lorempixel.com/400/400", PhoneNumber="0657373660", Appointments= new List<Appointment>() },
            new Visitor { FirstName="Eleina", LastName="Nieborg", Email="eleinanieborg@outlook.com", Company="Windesheim", Image="http://lorempixel.com/400/400", PhoneNumber="0641401035", Appointments = new List<Appointment>() },
            new Visitor { FirstName="Roy", LastName="Stobbelaar", Email="roystobbelaar@hotmail.com", Company="BelastingDienst", Image="http://lorempixel.com/400/400", PhoneNumber="0637628563", Appointments = new List<Appointment>() },
            new Visitor { FirstName="Michel", LastName="Vaassen", Email="maf.vaassen@belastingdienst.nl", Company="BelastingDienst", Image="http://lorempixel.com/400/400", PhoneNumber="0638572843", Appointments= new List<Appointment>() }
        };

        visitors.ForEach(v => context.Visitors.AddOrUpdate(s => s.Email, v));
        context.SaveChanges();

        visitors[0].Appointments.Add(appointments[0]);
        visitors[1].Appointments.Add(appointments[0]);
        visitors[3].Appointments.Add(appointments[0]);

        visitors[3].Appointments.Add(appointments[1]);
        visitors[2].Appointments.Add(appointments[1]);

        visitors[0].Appointments.Add(appointments[2]);
        visitors[1].Appointments.Add(appointments[2]);
        visitors[4].Appointments.Add(appointments[2]);

        context.SaveChanges();

        var collectors = new List<Collector>
        {
            new Collector { Appointment = appointments.FirstOrDefault(x => x.ID == 1), Employee = employees.FirstOrDefault(x => x.ID == 7), Preference = 1}, //employeeID = signle).id
            new Collector { Appointment = appointments.FirstOrDefault(x => x.ID == 1), Employee = employees.FirstOrDefault(x => x.ID == 8), Preference = 2},
            new Collector { Appointment = appointments.FirstOrDefault(x => x.ID == 1), Employee = employees.FirstOrDefault(x => x.ID == 9), Preference = 3},

            new Collector { Appointment = appointments.FirstOrDefault(x => x.ID == 2), Employee = employees.FirstOrDefault(x => x.ID == 8), Preference = 1},

            new Collector { Appointment = appointments.FirstOrDefault(x => x.ID == 3), Employee = employees.FirstOrDefault(x => x.ID == 9), Preference = 1},
            new Collector { Appointment = appointments.FirstOrDefault(x => x.ID == 3), Employee = employees.FirstOrDefault(x => x.ID == 7), Preference = 2},

        };

        collectors.ForEach(c => context.Collectors.AddOrUpdate(p => p.ID, c));
        context.SaveChanges();

        appointments[0].Collectors.Add(collectors[0]);
        appointments[0].Collectors.Add(collectors[1]);
        appointments[0].Collectors.Add(collectors[2]);

        appointments[1].Collectors.Add(collectors[3]);

        appointments[2].Collectors.Add(collectors[4]);
        appointments[2].Collectors.Add(collectors[5]);

        context.SaveChanges();

        appointments[0].Visitors.Add(visitors[0]);
        appointments[0].Visitors.Add(visitors[1]);
        appointments[0].Visitors.Add(visitors[3]);

        appointments[1].Visitors.Add(visitors[3]);
        appointments[1].Visitors.Add(visitors[2]);

        appointments[2].Visitors.Add(visitors[0]);
        appointments[2].Visitors.Add(visitors[1]);
        appointments[2].Visitors.Add(visitors[4]);

        context.SaveChanges();

    }
}

我很抱歉代码的数量,但导致这个问题的所有代码都在那里,所以我希望有人可以帮助我!

请告诉我我需要做些什么来永远摆脱这个问题。我将永远为你负债!

修改-虽然写入

在我发布此答案之前,我正在浏览可能有答案的问题,我发现This SO post.

提到以下内容:

  

正在发生的事情是你的对象的主键都有默认的int值(0)。当您将它们添加到上下文中时,EF检测到这一点并抛出错误(两个相同类型的对象不能具有相同的密钥,在本例中为0.我假设数据库中的主键字段设置为IDENTITY列并且将插入时自动增加+1。这可能听起来很奇怪,但您需要为对象提供占位符ID,这些ID将在插入时替换为IDENTITY值。

我将种子代码的第一部分更改为以下内容:

protected override void Seed(BezoekersDBContext context)
{
    var employees = new List<Employee>
    {
        new Employee { ID = 1,FirstName="Jan", LastName="Scholten", Email="JanScholten2948@outlook.com", Image="http://lorempixel.com/400/400", PhoneNumber="0675876573", SAP_ID= 20149203, Appointments = new List<Appointment>()},
        new Employee { ID = 2,FirstName="Bart", LastName="de Vries", Email="BartDeVries23@outlook.com", Image="http://lorempixel.com/400/400", PhoneNumber="0655544422", SAP_ID=20148394, Appointments = new List<Appointment>()},
        new Employee { ID = 3,FirstName="Denke", LastName="Eekhoorn", Email="DenkeEekhoorn39@gmail.com", Image="http://lorempixel.com/400/400", PhoneNumber="0674738383", SAP_ID=2039388, Appointments = new List<Appointment>() }
    };

    employees.ForEach(e => context.Employees.AddOrUpdate(p => p.SAP_ID, e));
    context.SaveChanges();

    var appointments = new List<Appointment>
    {
        new Appointment { Employee = employees.FirstOrDefault(e => e.ID == 7),Location = "Apeldoorn", Comment="Rolstoeltoegang is nodig!", Date = new DateTime(2015, 11, 12, 13, 14, 0), Visitors = new List<Visitor>(), Collectors = new List<Collector>() },
        new Appointment { Employee = employees.FirstOrDefault(e => e.ID == 8),Location = "Zwolle", Comment="Kan laat zijn.", Date = new DateTime(2016,2,11,14,12,0), Visitors = new List<Visitor>(), Collectors = new List<Collector>() },
        new Appointment { Employee = employees.FirstOrDefault(e => e.ID == 9),Location="Amsterdam", Comment="Geen speciale opmerking", Date = new DateTime(2015,12,18,15,15,0), Visitors = new List<Visitor>(), Collectors = new List<Collector>() }
    };

    //Other code here

这给了我以下错误

序列包含多个元素

堆栈跟踪的更大部分:

System.InvalidOperationException: Sequence contains more than one element
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__2[TResult](IEnumerable`1 sequence)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
   at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
   at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
   at System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate[TEntity](DbSet`1 set, IEnumerable`1 identifyingProperties, InternalSet`1 internalSet, TEntity[] entities)
   at System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate[TEntity](IDbSet`1 set, Expression`1 identifierExpression, TEntity[] entities)
   at BezoekersRegistratie_BackEnd2.Migrations.Configuration.<>c__DisplayClass1_0.<Seed>b__0(Employee e) in C:\BezoekersRegistratie\Stagiairs\Reinold Boeve\BezoekersRegistratie_BackEnd2\BezoekersRegistratie_BackEnd2\Migrations\Configuration.cs:line 26
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at BezoekersRegistratie_BackEnd2.Migrations.Configuration.Seed(BezoekersDBContext context) in C:\BezoekersRegistratie\Stagiairs\Reinold Boeve\BezoekersRegistratie_BackEnd2\BezoekersRegistratie_BackEnd2\Migrations\Configuration.cs:line 26

我觉得我离我更近了。有人可以帮我解决这个问题吗?

0 个答案:

没有答案