2015-06-06 45 views
1

我正努力在DbContext上实现一个非常基本的“InsertOrUpdate()”方法。我试着按照this post的建议。努力在DbContext上实现通用的InsertOrUpdate()

private static bool SaveItem<TEntity>(Object objToSave, TEntity existing = null) where TEntity : class 
{ 
    try 
    { 
     ///////////////////////////////////////// 
     // BLOCK A 
     if(existing != null) 
      db.Set<TEntity>().Attach(existing); 
     ///////////////////////////////////////// 
     db.Entry(objToSave).State = existing!=null ? EntityState.Modified : EntityState.Added; 
     db.SaveChanges(); 
    } catch(Exception e) 
    { 
     Logger.Exception(e); 
     return false; 
    } 
    return true; 
} 

一个例子调用如下:

SaveItem(item, db.MyInstances.Where(dbItem => dbItem.ID == item.ID).FirstOrDefault()); 

一些定义:

class MyInstancesDbContext: DbContext { ... } 
private static MyInstancesDbContext db = new MyInstancesDbContext(); 

据我了解,在拨打.Where()会导致某种形式的附件。所以我已经尝试了包括标记为“A”的小块代码并将其删除。这两者给我同样的错误类型:

System.InvalidOperationException: Attaching an entity of type '...MyInstance' failed because a nother entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any en tities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the ' Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

我发现this popular related answer这个错误的用户建议使用AsNoTracking(),但是这反而让我觉得我没有从根本上理解的东西或我试图忽视一些错误。

我非常感谢任何建议。

+0

为什么类型的''objToSave'和Object''existing'是'TEntity'?他们不应该一样吗? – jjj

回答

0

我想你错过的是DbContext跟踪实体,它不喜欢使用相同的主键跟踪相同类型的实体。

  1. 当调用此:

    db.MyInstances.Where(dbItem => dbItem.ID == item.ID).FirstOrDefault() 
    

    已加载的MyInstance与主键== item.ID实体进入情境,如果它存在于数据库中。

  2. 此行完全不需要,因为existing已经连接 - 但可能不会导致错误。

    if(existing != null) 
        db.Set<TEntity>().Attach(existing); 
    
  3. 这个问题可能是在这里:

    db.Entry(objToSave).State = 
    existing != null ? EntityState.Modified : EntityState.Added; 
    

    如果existing == null,你可能是正确的,因为这条线将连接objToSave,但如果existing存在,你就会有,因为你的问题”将尝试附加与existing具有相同类型和主键的objToSave


相反,你可以尝试使用objToSave为连接实体设置的值:

db.Entry(existing).CurrentValues.SetValues(objToSave); 

所以objToSave不会,如果有一个现有的记录连接。

https://msdn.microsoft.com/en-us/data/jj592677.aspx