C# 更新EF 6中的现有数据会引发异常-“;。。。相同类型的实体已具有相同的主键值。”;
我正在尝试使用EntityFramework6更新记录,代码优先,没有流畅的映射或者像Automapper这样的工具 实体(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
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;
}
我不断得到错误:
附加类型为的实体失败,因为另一个实体的类型相同
类型已具有相同的主键值。当
使用“附加”方法或将实体的状态设置为
“未更改”或“已修改”,如果图形中的任何实体
键值冲突。这可能是因为某些实体是新的且
尚未收到数据库生成的键值。在本例中,请使用
“添加”方法或“添加”实体状态来跟踪图形和
然后将非新实体的状态设置为“未更改”或“已修改”,如下所示
合适
我尝试了以下方法:
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。我有导航属性(在复合类ikeAddress
和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;
}