[英]Saving AutoMapper mapped Collections of Entities using Entity Framework
[英]Use AsNoTracking for entities mapped from AutoMapper
我有一种情况,我正在使用自动映射器映射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 : AsNoTracking()
我需要使用AsNoTracking()
,我不确定如何在AutoMapper
使用它吗?
有什么建议么?
AsNoTracking指的是何时由上下文而不是由Automapper加载实体。 之所以会收到错误,是因为在DbContext生命的某个时刻,它已使用该ID加载了实体并正在对其进行跟踪。 他们建议的选项是将您的实体加载切换为使用AsNoTracking,这可以有效地告诉EF在读取实体时不要跟踪该实体。
解决该问题的另一种方法是先检查DbContext的本地缓存中是否存在该实体,如果找到该实体,则使用AutoMapper将属性更改映射到该现有实体,而不是创建一个新实体。
例如:
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端点,则可以利用此漏洞允许用户编辑原本不应该的记录,或者以不应该的方式更新记录。 (不要从客户端请求中获得任何信任。)每个请求都应经过彻底验证,并且检测到的任何偏差都应终止客户端会话。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.