简体   繁体   English

当数据已存在于数据库中时,EF Seed不工作

[英]EF Seed not working when data already in database

First time creating DB and running Seed method works fine. 第一次创建DB并运行Seed方法工作正常。 It throws error on second run when data is already in the database. 当数据已存在于数据库中时,它会在第二次运行时抛出错误。

I also noticed that when I assign property to entity, its PropertyId is not updated and stays null. 我还注意到,当我将属性分配给实体时,其PropertyId不会更新并保持为null。

This is my code. 这是我的代码。

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

This is exception message on third SaveChanges: 这是第三个SaveChanges上的异常消息:

The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_dbo.MonitoringTasks_dbo.Jobs_JobId". UPDATE语句与FOREIGN KEY约束“FK_dbo.MonitoringTasks_dbo.Jobs_JobId”冲突。 The conflict occurred in database "StreetStats", table "dbo.Jobs", column 'Id'. 冲突发生在数据库“StreetStats”,表“dbo.Jobs”,列“Id”中。

Every FK relation looks like 每个FK关系看起来像

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

Look at the entity state of job after its AddOrUpdate call in the second run. 在第二次运行中调用AddOrUpdate后,查看实体的job状态。 You can do this like so: 你可以这样做:

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

You'll see that it's Detached . 你会看到它是Detached Still, if you do ... 不过,如果你这样做......

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

... you'll see that in reality the job is attached to the context! ......你会发现实际上这份工作与上下文有关!

This a known bug in AddOrUpdate . 这是AddOrUpdate一个已知错误 The instance that's actually attached to the context is hidden from your method scope, and job is a second instance that EF doesn't know of. 实际附加到上下文的实例对方法范围是隐藏的,而job是EF不知道的第二个实例。

That causes all kinds of misery. 这会造成各种各样的痛苦。 The job you connect with monitoringTask will be seen as a new instance and EF will try to insert it. 您与monitoringTask连接的作业将被视为新实例,EF将尝试插入它。 I'm not sure why you get a foreign key exception (I would have expected a unique key violation) but I think that has to do with primary key column type and whether or not it has an identity specification. 我不确定为什么你得到一个外键异常(我本来期望一个唯一的密钥违规)但我认为这与主键列类型有关,以及它是否具有标识规范。

Anyway, the work-around is to do ... 无论如何,解决方法是......

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

... and so on, for each AddOrUpdate call of which you intend to use the objects later. ...等等,对于您打算稍后使用这些对象的每个AddOrUpdate调用。 This makes the actually attached (but hidden) objects equal to the ones visible to you. 这使得实际附加(但隐藏)的对象等于您可见的对象。

I noticed this also; 我也注意到了这一点; just add the Id field for each property you are adding in your seed method. 只需为种子方法中添加的每个属性添加Id字段。

ie

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

This worked for me. 这对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM