首次创建数据库并运行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; }
答案 0 :(得分:3)
在第二次运行中job
调用之后查看AddOrUpdate
的实体状态。你可以这样做:
Debug.WriteLine(context.Entry(job).State);
你会看到它是Detached
。不过,如果你这样做......
Debug.WriteLine(context.Jobs.Local.First().Name);
...你会发现实际上这份工作与背景有关!
AddOrUpdate
中的known bug。实际附加到上下文的实例对您的方法范围隐藏,而job
是EF不知道的第二个实例。
这会导致各种痛苦。您与monitoringTask
连接的作业将被视为新实例,EF将尝试插入它。我不确定为什么你会得到一个外键异常(我本来期望一个唯一的密钥违规),但我认为这与主键列类型有关,是否有标识规范。
无论如何,解决方法是......
context.Workers.AddOrUpdate(w => w.Name, worker);
context.SaveChanges();
worker = context.Workers.Local.Single(w => w.Name == worker.Name);
...依此类推,对于您打算稍后使用这些对象的每个AddOrUpdate
调用。这使得实际连接(但隐藏)的对象等于您可见的对象。
答案 1 :(得分:0)
我也注意到了这一点;只需为种子方法中添加的每个属性添加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();
这对我有用。