【问题标题】:EF Seed not working when data already in database当数据库中已有数据时,EF Seed 不起作用
【发布时间】:2015-12-21 20:57:52
【问题描述】:

第一次创建数据库并运行Seed 方法工作正常。当数据已经在数据库中时,它会在第二次运行时引发错误。

我还注意到,当我将属性分配给实体时,它的PropertyId 没有更新并保持为空。

这是我的代码。

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

【问题讨论】:

    标签: c# .net sql-server entity-framework orm


    【解决方案1】:

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

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

    您会看到它是Detached。不过,如果你这样做......

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

    ...您会看到,实际上工作是依附于上下文的!

    这是known bug 中的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 调用。这使得实际附加(但隐藏)的对象与您可见的对象相同。

    【讨论】:

    • 谢谢。这解决了它。我想我会写我自己的 AddOrUpdate 扩展方法。他们是如何在测试中错过的?这是我第一次接触 EF,我在使用它的前 10 分钟就发现了。
    【解决方案2】:

    我也注意到了这一点;只需为您在种子方法中添加的每个属性添加 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();
    

    这对我有用。

    【讨论】:

      猜你喜欢
      • 2019-10-12
      • 1970-01-01
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-07
      • 1970-01-01
      相关资源
      最近更新 更多