当数据已在数据库中时,EF种子不起作用

本文关键字:EF 种子 不起作用 数据 数据库 | 更新日期: 2023-09-27 18:27:35

第一次创建DB并运行Seed方法效果良好。当数据已经在数据库中时,它在第二次运行时抛出错误。

我还注意到,当我将属性分配给实体时,它的PropertyId不会更新并且保持为null。

这是我的密码。

protected override void Seed(StreetStats.Data.StreetStatsDbContext context)
{
    if (System.Diagnostics.Debugger.IsAttached == false)
        System.Diagnostics.Debugger.Launch();
    using (context.Database.BeginTransaction())
    {
        try
        {
            Worker worker = new Worker()
            {
                Name = "Worker 1",
            };
            context.Workers.AddOrUpdate(w => w.Name, worker);
            context.SaveChanges(); //Worker gets Id assigned to the existing worker with the same name in DB
            Job job = new Job()
            {
                Name = "Job 1",                     
                Worker = worker
            };
            context.Jobs.AddOrUpdate(j => j.Name, job);
            context.SaveChanges(); //WorkerId is null for some reason
            MonitoringTask monitoringTask = new MonitoringTask
            {
                Job = job,
                Name = "Task 1"                     
            };
            context.MonitoringTasks.AddOrUpdate(mt => mt.Name, monitoringTask);
            context.SaveChanges(); //Throws exception
            Area area = new Area
            {
                MonitoringTask = monitoringTask,
                Name = "Area 1"                     
            };
            context.Areas.AddOrUpdate(a => a.Name, area);
            context.SaveChanges();
            context.Database.CurrentTransaction.Commit();
        }
        catch (Exception)
        {
            context.Database.CurrentTransaction.Rollback();
            throw;
        }
    }
}

这是第三个SaveChanges:上的异常消息

UPDATE语句与FOREIGN KEY约束"FK_dbo.MonitoringTasks_dbo.Jobs_JobId"冲突。冲突发生在数据库"StreetStats"表"dbo.Jobs"列"Id"中。

每个FK关系看起来都像

Worker Worker { get; set; }
Int64 WorkerId { get; set; }

当数据已在数据库中时,EF种子不起作用

在第二次运行AddOrUpdate调用后查看job的实体状态。你可以这样做:

Debug.WriteLine(context.Entry(job).State);

你会看到它是Detached。尽管如此,如果你这样做。。。

Debug.WriteLine(context.Jobs.Local.First().Name);

你会发现,在现实中,这份工作是附属于上下文的!

这是AddOrUpdate中已知的错误。实际附加到上下文的实例对方法范围是隐藏的,而job是EF不知道的第二个实例。

这造成了各种各样的痛苦。与monitoringTask连接的作业将被视为一个新实例,EF将尝试插入它。我不确定为什么会出现外键异常(我本以为会出现唯一密钥冲突),但我认为这与主键列类型以及它是否有标识规范有关。

不管怎样,周围的工作就是。。。

context.Workers.AddOrUpdate(w => w.Name, worker);
context.SaveChanges();
worker = context.Workers.Local.Single(w => w.Name == worker.Name);

依此类推,对于以后要使用对象的每个AddOrUpdate调用。这使得实际附着(但隐藏)的对象与您可见的对象相等。

我也注意到了这一点;只需为您在种子方法中添加的每个属性添加Id字段。

Worker worker = new Worker()
{
    WorkerId = 1,
    Name = "Worker 1",
};
context.Workers.AddOrUpdate(w => w.Name, worker);
context.SaveChanges();
Job job = new Job()
{
    JobId = 1,
    Name = "Job 1",                     
    Worker = worker.WorkerId
};
context.Jobs.AddOrUpdate(j => j.Name, job);
context.SaveChanges(); //WorkerId is null for some reason
MonitoringTask monitoringTask = new MonitoringTask
{
    MonitoringTaskId = 1,
    Job = job.JobId,
    Name = "Task 1"                     
};
context.MonitoringTasks.AddOrUpdate(mt => mt.Name, monitoringTask);
context.SaveChanges();

这对我很有效。