我遇到了使用自动映射器映射DTO->数据库实体的情况。
var entityObj = _mapper.Map<REQUESTEXT>(reqDTO);
然后我正在使用entityObj
更新数据库中的记录。
void Update(REQUESTEXT entityObj)
{
_context.REQUESTEXTs.Attach(entityObj); <--- Error
_context.Entry(entityObj).Property(x => x.CUSTOPTIONCD).IsModified = true;
_context.SaveChanges();
}
当我尝试将REQUESTEXT
对象附加到上下文时,它给我一个错误:
附加类型为'A'的实体失败,因为 相同类型已经具有相同的主键值。这可能发生在 使用“附加”方法或将实体的状态设置为 如果图中的任何实体具有“未更改”或“已修改” 关键值冲突。这可能是因为某些实体是新的, 尚未收到数据库生成的键值。在这种情况下使用 “添加”方法或“已添加”实体状态来跟踪图形和 然后将非新实体的状态设置为“未更改”或“已修改”,如下所示: 合适的。
根据此SO答案:https://stackoverflow.com/a/23228001/1169180我需要使用AsNoTracking()
,我不确定如何在AutoMapper
中使用它吗?
有什么建议吗?
答案 0 :(得分:0)
AsNoTracking指的是何时由上下文而不是由Automapper加载实体。之所以会收到错误,是因为在DbContext生命的某个时刻,它已使用该ID加载了实体并正在对其进行跟踪。他们推荐的选项是切换您的实体加载以使用AsNoTracking,它可以有效地告诉EF not 在读取实体时对其进行跟踪。
该问题的另一种解决方案是先检查DbContext的本地缓存中是否存在该实体,如果找到该实体,则使用AutoMapper将属性更改映射到该现有实体,而不是创建一个新实体。 / p>
例如:
var existingEntity = _context.REQUESTEXTs.Local.SingleOrDefault(x => x.EntityId == reqDTO.EntityId);
if(existingEntity != null)
mapper.Map(reqDto, existingEntity);
else
{
var entityObj = _mapper.Map<REQUESTEXT>(reqDTO);
_context.REQUESTEXTs.Attach(entityObj);
_context.Entry(entityObj).Property(x => x.CUSTOPTIONCD).IsModified = true;
}
_context.SaveChanges();
这将检查现有实体的本地缓存(不命中数据库),如果找到,它将使用AutoMapper更新其属性。实体跟踪将记录这些更改,因此,在调用SaveChanges时,修改将进入数据库。如果本地缓存中没有该实体,则我们将创建一个新实例,将其附加,将其标记为已修改,然后保存。
您的示例中似乎缺少一个建议:您应该验证以下假设:
如果这是Web应用程序/带有可访问的Controller动作或Web API端点,则可以利用此漏洞允许用户编辑原本不应该的记录,或者以不应该的方式更新记录。 (不要信任客户请求。)每个请求都应经过彻底验证,并且发现的任何偏差都应终止客户会话。