繁体   English   中英

对从AutoMapper映射的实体使用AsNoTracking

[英]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时,修改将进入数据库。 如果本地缓存中没有该实体,那么我们将创建一个新实例,将其附加,将其标记为已修改,然后保存。

您的示例中似乎缺少一个建议:您应该验证以下假设:

  • 尝试执行此操作之前,DTO中的ID实际上确实存在于数据库中。
  • 正在修改的记录可以并且应该可以由发出此请求的用户编辑。
  • 正在更新的数据已完全验证。

如果这是一个Web应用程序/带有可访问的Controller动作或Web API端点,则可以利用此漏洞允许用户编辑原本不应该的记录,或者以不应该的方式更新记录。 (不要从客户端请求中获得任何信任。)每个请求都应经过彻底验证,并且检测到的任何偏差都应终止客户端会话。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM