更新EF 6中的现有数据会引发异常 - "...相同类型的实体已具有相同的主键值".

use*_*426 7 c# entity-framework entity-framework-6

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

entity(Employee)具有与之关联的其他复合属性,如Addreess(collection),Department

它也是从一个名为的基础继承的 User

save方法如下,_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;

        }
Run Code Online (Sandbox Code Playgroud)

我一直收到错误:

附加类型的实体失败,因为相同类型的另一个实体已具有相同的主键值.如果图中的任何实体具有冲突的键值,则在使用"附加"方法或将实体的状态设置为"未更改"或"已修改"时,可能会发生这种情况.这可能是因为某些实体是新的并且尚未收到数据库生成的键值.在这种情况下,使用"添加"方法或"已添加"实体状态来跟踪图形,然后根据需要将非新实体的状态设置为"未更改"或"已修改".

我尝试过以下方法:

  1. 在设置之前附加 EntityState.Modified
  2. 添加AsNoTracking()查询对象是否存在(没有例外,但DB没有更新) - /sf/answers/1625960101/
  3. 使用基本实体_dbContext.Users而不是Employee实体进行保存 - /sf/answers/1790294411/

现在这些都不适合我.

对于那些不能在我的情况下工作的解决方案,我有什么问题?

ESG*_*ESG 22

假设您没有要更新的导航属性,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;

    }
Run Code Online (Sandbox Code Playgroud)

这通常会生成更好的SQL语句,因为它只会更新已更改的属性.

如果你仍然想使用原始方法,你将摆脱entity上下文,使用AsNoTracking(不知道为什么它没有在你的情况下更新,它应该没有效果,所以问题可能是其他的)或者修改您的查询以防止它首先使用类似的东西来实现实体bool exists = dbContext.Employees.Any(c => c.Id == employee.Id).


小智 6

这对我自己有用

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;
}
Run Code Online (Sandbox Code Playgroud)