【问题标题】:Struggling to implement a generic InsertOrUpdate() on DbContext努力在 DbContext 上实现通用的 InsertOrUpdate()
【发布时间】:2015-06-06 18:56:44
【问题描述】:

我正在努力在 DbContext 上实现一个非常基本的“InsertOrUpdate()”方法。我尝试按照this post 中的建议进行操作。

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:附加类型为“...MyInstance”的实体失败,因为 相同类型的其他实体已经具有相同的主键值。当使用“附加”方法或将实体的状态设置为“未更改”或“已修改”(如果有)时,可能会发生这种情况 图中的 tities 具有冲突的键值。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“ 添加了实体状态来跟踪图表,然后将非新实体的状态设置为“未更改”或“已修改”。

我在用户建议使用AsNoTracking() 的错误中找到了this popular related answer,但这反而让我觉得我没有从根本上理解某些东西或试图忽略一些错误。

如果有任何建议,我将不胜感激。

【问题讨论】:

  • 为什么objToSave 类型为ObjectexistingTEntity?他们不应该是一样的吗?

标签: c# entity-framework


【解决方案1】:

我认为您缺少的是 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存在,你会遇到问题,因为你将尝试附加objToSave,它具有相同的类型和主键为existing


相反,您可以尝试使用objToSave 设置附加实体的值:

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

所以objToSave如果有现有记录就不会附加。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-27
    • 2020-01-31
    • 2013-12-30
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多