Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 更新EF 6中的现有数据会引发异常-“;。。。相同类型的实体已具有相同的主键值。”;_C#_Entity Framework_Entity Framework 6 - Fatal编程技术网

C# 更新EF 6中的现有数据会引发异常-“;。。。相同类型的实体已具有相同的主键值。”;

C# 更新EF 6中的现有数据会引发异常-“;。。。相同类型的实体已具有相同的主键值。”;,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,我正在尝试使用EntityFramework6更新记录,代码优先,没有流畅的映射或者像Automapper这样的工具 实体(Employee)具有与之关联的其他复合属性,如addrees(集合),部门 它也从名为User 保存方法如下所示,\u dbContext是DbConext实现 public bool UpdateEmployee(Employee employee) { var entity = _dbContext.Employ

我正在尝试使用EntityFramework6更新记录,代码优先,没有流畅的映射或者像Automapper这样的工具

实体(
Employee
)具有与之关联的其他复合属性,如
addrees
(集合),
部门

它也从名为
User

保存方法如下所示,
\u dbContext
DbConext
实现

        public bool UpdateEmployee(Employee employee)
        {
            var entity = _dbContext.Employees.Where(c => c.Id == employee.Id).AsQueryable().FirstOrDefault();
            if (entity == null)
            {
                _dbContext.Employees.Add(employee);
            }
            else
            {
                _dbContext.Entry(employee).State = EntityState.Modified; // <- Exception raised here
                _dbContext.Employees.Attach(employee);

            }

            return _dbContext.SaveChanges() > 0;

        }
public bool UpdateEmployee(员工)
{
var entity=_dbContext.Employees.Where(c=>c.Id==employee.Id).AsQueryable().FirstOrDefault();
if(实体==null)
{
_dbContext.Employees.Add(employee);
}
其他的
{
_dbContext.Entry(employee.State=EntityState.Modified;//0;
}
我不断得到错误:

附加类型为的实体失败,因为另一个实体的类型相同 类型已具有相同的主键值。当 使用“附加”方法或将实体的状态设置为 “未更改”或“已修改”,如果图形中的任何实体 键值冲突。这可能是因为某些实体是新的且 尚未收到数据库生成的键值。在本例中,请使用 “添加”方法或“添加”实体状态来跟踪图形和 然后将非新实体的状态设置为“未更改”或“已修改”,如下所示 合适

我尝试了以下方法:

  • 在设置为EntityState.Modified之前附加
  • 在查询对象是否存在时添加
    AsNoTracking()
  • 使用基本实体
    \u dbContext.Users
    而不是员工实体保存-
  • 现在这些都不适合我了


    如果某些解决方案在我的情况下不起作用,我会犯什么错误呢?

    EF已经提供了一种无需借助Automapper即可映射属性的方法,假设您没有要更新的导航属性:

    public bool UpdateEmployee(Employee employee)
        {
            var entity = _dbContext.Employees.Where(c => c.Id == employee.Id).AsQueryable().FirstOrDefault();
            if (entity == null)
            {
                _dbContext.Employees.Add(employee);
            }
            else
            {
                _dbContext.Entry(entity).CurrentValues.SetValues(employee);              
            }
    
            return _dbContext.SaveChanges() > 0;
    
        }
    
    这通常会生成更好的SQL语句,因为它只会更新已更改的属性


    如果您仍然希望使用原始方法,您将从上下文中删除
    实体
    ,或者使用AsNoTracking(不确定在您的情况下它为什么没有更新,它应该没有效果,因此问题可能是其他原因)或者,在修改查询以防止它首先具体化实体时,使用类似于
    bool exists=dbContext.Employees.Any(c=>c.Id==employee.Id)
    的方法。例如,您需要分离以避免调用SaveChanges时出现重复的主键异常

    db.Entry(entity).State = EntityState.Detached;
    
    这对我来说很有效

    var aExists = _db.Model.Find(newOrOldOne.id);
    if(aExists==null)
    {
        _db.Model.Add(newOrOldOne);
    }
    else
    {
        _db.Entry(aExists).State = EntityState.Detached;
        _db.Entry(newOrOldOne).State = EntityState.Modified;
    }
    

    我在使用存储库和工作单元模式时遇到了同样的问题(如中所述)

    GenericRepository包含一个更新(TEntity)方法,该方法尝试附加然后设置条目。State=Modified。如果您要坚持uow/repo模式,则上面的“答案”无法解决此问题

    在附加之前,我确实尝试过使用分离过程,但它仍然失败,原因与最初问题中指出的相同

    原因是,我在检查记录是否存在,然后在调用update()之前使用automapper从我的dto生成一个实体对象

    通过检查该记录的存在性,我将实体对象放在范围内,但无法将其分离(这也是初始提问者无法分离的原因)…Tt跟踪记录,在我将dto自动映射到实体中并尝试更新后,不允许进行任何更改

    以下是通用回购协议的更新实施:

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
    
    这是我的PUT方法(我将WebApi与Angular一起使用)

    [HttpPut]
    公共IHttpActionResult Put(内部id、产品)
    {
    IHttpActionResult-ret;
    尝试
    {
    //删除预检查,因为它会锁定记录
    //var e=unitOfWork.ProductRepository.GetByID(id);
    //如果(e!=null){
    var toSave=_mapper.Map(产品);
    unitOfWork.ProductRepository.Update(保存);
    unitOfWork.Save();
    var p=_mapper.Map(toSave);
    ret=正常(p);
    // }
    //否则
    //ret=NotFound();
    }
    捕获(DbEntityValidationException ex)
    {
    ret=BadRequest(ValidationErrorsToMessages(ex));
    }
    捕获(例外情况除外)
    {
    ret=内部服务器错误(ex);
    }
    返回ret;
    }
    
    正如您所看到的,我已经注释掉了我的检查,以查看该记录是否存在。我想如果我尝试更新一条不再存在的记录,我将看到它是如何工作的,因为我不再有NotFound()返回机会


    因此,为了回答最初的问题,我会说在尝试之前不要查找entity==null,或者想出另一种方法。在我的情况下,我可以在发现对象后处理我的UnitOfWork,然后进行更新。

    使用
    var entity=\u dbContext.Employees.FirstOrDefault(c=>c.Id==employee.Id)
    dbContext的寿命是多少?我打赌你创建新上下文的次数不够多。请看我的答案。我说过我没有使用Automapper。我有导航属性(在复合类ike
    Address
    Department
    中。你是说我需要Automapper吗?。你的代码没有导致异常,但数据库没有更新。你是在修改对象的属性还是其他什么?如果你修改的是整个对象图,你必须遍历该图并标记所有的站点ms已修改。我有一个
    员工
    记录,我想使用Enty Framework(它的新功能)更新该记录。就我的研究而言
    [HttpPut]
    public IHttpActionResult Put(int id, Product product)
    {
        IHttpActionResult ret;
        try
        {
            // remove pre-check because it locks the record
            // var e = unitOfWork.ProductRepository.GetByID(id);
            //  if (e != null) {
            var toSave = _mapper.Map<ProductEntity>(product);
            unitOfWork.ProductRepository.Update(toSave);
            unitOfWork.Save();
            var p = _mapper.Map<Product>(toSave);
            ret = Ok(p);
            // }
            // else
            //    ret = NotFound();
        }
        catch (DbEntityValidationException ex)
        {
            ret = BadRequest(ValidationErrorsToMessages(ex));
        }
        catch (Exception ex)
        {
            ret = InternalServerError(ex);
        }
        return ret;
    }