3

如果我修改POCO實體的屬性,但重置它,則EntityFramework仍會說有變化。爲什麼實體框架檢測到已修改但已重置的屬性的更改?

Property "Name": Value "Test" (original value) 
       -> Value "Test123" (value changed by UI) 
       -> Value "Test" (value changed by UI to original value) 

條目已被修改:

var objectStateEntries = 
    _db.ObjectStateManager.GetObjectStateEntries(
     EntityState.Added | 
     EntityState.Deleted | 
     EntityState.Modified); 

你怎麼處理這種情況?

+0

您的POCO實體是一個動態代理(=所有屬性都是'virtual')? – Slauma

+0

是的,他們是虛擬的。 – Rookian

+2

我認爲這是因爲你實際上沒有「重置」價值,而是「重新設置」它。除非每次檢查未修改的值,否則EF如何知道它已更改回原始值? –

回答

7

如果您的所有屬性都是virtual默認情況下,Entity Framework會自動爲您的POCO創建一個動態代理。如果我沒看錯的變化跟蹤是基於在這種情況下,在這個動態對象的屬性setter,大致是這樣:

private string _name; 
public string Name 
{ 
    // ... 
    set 
    { 
     // if (_name != value) such a check probably does not happen 
     { 
      _name = value; 
      MarkPropertyAsModified(...); 
     } 
    } 
} 

因此,不存在與原值無法相比,但只的當前值屬性。如果此值發生更改,則無論將其重置爲原始值,該屬性都會被標記爲已修改。

(上段編輯和修正:!爲已修改屬性標記,如果設置器調用,如果相同或改變的值賦給感謝Brad托馬斯和低於他的評論無論)

可避免在上下文選項禁用此創建動態代理:

objectContext.ContextOptions.ProxyCreationEnabled = false; 

變化檢測現在依靠快照創建,這意味着EF比較原始值(存儲在快照中的對象上下文)與當前值當更改檢測被稱爲。這不會發生在屬性設置器中,而是在Entity Framework的某些功能中發生,例如在SaveChanges中。在您的情況下,這意味着當您撥打SaveChanges原始值(快照)和當前值將是相同的,因爲您已重置更改。基本上EF沒有注意到你改變了財產兩次,並認爲財產沒有改變。

請注意,禁用代理創建 - 如果全局執行(例如在上下文構造函數中),這對您的應用程序而言可能是一個深刻的變化。您可能有依賴於動態代理的代碼才能正常工作,並且在各種情況下也會嚴重影響性能。存在動態代理來快速更改跟蹤。基於快照的更改跟蹤速度要慢得多。

+0

感謝您的簡單解釋 – Rookian

+0

@Slauma您還應該提到,如果該屬性不是虛擬的,則不會跟蹤代理跟蹤。這樣用戶可以避免在整個上下文中使用ProxyCreation。 – JotaBe

+1

@Slauma屬性被標記爲已修改,即使它們的值在進行分配調用時未被更改。這很容易證明,只需在將屬性賦值給它之前和之後檢查EntityState即可。所以我認爲你的代碼示例是不準確的。問題在於「修改」有明顯的語義差異,即有修改嘗試或「修改」,即原始值和當前值是否有所不同。 Entity Framework使用EntityState的第一個含義 –

0

對於動態代理對象,一旦更改屬性值,上下文將其標記爲已更改。

相關問題