2015-12-21 23 views
1

首次創建數據庫並運行Seed方法正常工作。當數據已經在數據庫中時,它會在第二次運行時拋出錯誤。當數據已經在數據庫中時,EF種子不工作

我還注意到,當我將屬性分配給實體時,其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語句衝突與外鍵約束 「FK_dbo.MonitoringTasks_dbo.Jobs_JobId」。衝突發生在數據庫「StreetStats」,表「dbo.Jobs」,列'Id'中。

每FK關係看起來像

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

回答

3

看那job實體狀態它在第二輪AddOrUpdate通話後。你可以這樣做:

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

你會看到它是Detached。不過,如果你這樣做......

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

......你會發現,在現實中,工作是附加到上下文!

This a known bug in 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調用其中的你打算以後使用的對象。這使得實際連接(但隱藏)的對象與您可見的對象相同。

+0

謝謝。這固定了它。我想我會寫我自己的AddOrUpdate擴展方法。 他們在測試中錯過了什麼?這是我第一次遇到EF,並且在使用它的前10分鐘裏找到了。 – Hooch

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

這爲我工作。

相關問題