EntityFramework 4.x 使用中遇到的问题 (1)

在目前项目里,使用Code First的模式,但数据库已经存在,并且在数据库中并未设立外键关系,但在实体类中定义了实体关系。以上为这次遇到问题的背景。

问题:

在保存一组数据的时候,提示出现主键重复的问题。

相关代码:

Dictionary<<Tuple<string, int>, Detail> details = ... // 该数据有方法外部传入
if(order.Details != null) // Order对象包含一个Detail对象的列表
{
    foreach(var d in order.Details.ToArray())
    {
         var key = Tuple.Create(d.Id, d.No);
         if(details.ContainKey(key))
         {
              // update the records with new value
              details.Remove(key);
         }
         else
         {
              dbContext.Entry(d).State = EntityState.Deleted;
         }
    }
    foreach(var d in details.Values)
    {
         dbContext.Details.Add(d);
    }
    dbContext.SaveChanges();
}

  

问题定位:

首先根据异常,找出引起错误的数据,发现要保存的数据并不存在重复情况,同时在数据库里存在该数据,按理说不应出现这个错误。

根据Log无法发现问题,只好调试程序了。当程序执行到var order = dbContext.Order.Find("id")的时候,发现数据库并不存在该id的数据,代码执行到这里,大概就已经发现了问题所在。由于数据里并不存在该id的数据,所以在前面Find的代码执行完毕后,根据输入的order数据创建了一个新的Order对象,这个时候,order的State是Added状态。当entry处于该状态时,在访问导航属性的时候,并不会尝试去数据库里读取Detail数据,所以执行上面的代码的时候,实际上是执行的dbContext.Details.Add(d)的部分。这也就造成了提示主键重复的异常。

解决:

既然是导航属性造成的问题,就只好选择绕开导航属性,直接通过Linq将Order数据读出来。

Dictionary<<Tuple<string, int>, Detail> details = ... // 该数据有方法外部传入
var detailsInDb = (from item in dbContext.Details where item.Id == order.Id select item).ToArray();
if(detailsInDb != null)
{
    foreach(var d in detailsInDb)
    {
         var key = Tuple.Create(d.Id, d.No);
         if(details.ContainKey(key))
         {
              // update the records with new value
              details.Remove(key);
         }
         else
         {
              dbContext.Entry(d).State = EntityState.Deleted;
         }
    }
    foreach(var d in details.Values)
    {
         dbContext.Details.Add(d);
    }
    dbContext.SaveChanges();
}

  

原文地址:https://www.cnblogs.com/FMax/p/2455985.html