簡體   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