2012-03-06 54 views
6

我試圖實現使用EF 4.1的審計日誌,通過如在以下地方討論重寫的SaveChanges()方法:實體框架的DbContext的SaveChanges()OriginalValue錯誤

雖然我遇到了「修改」條目的問題。無論何時我試圖獲取相關財產的原始價值,它始終與其在CurrentValue字段中的值相同。

我第一次使用此代碼,並將其成功地識別被修改的條目:

public int SaveChanges(string userID) 
{ 

    // Have tried both with and without the following line, and received same results: 
    // ChangeTracker.DetectChanges(); 

    foreach (
     var ent in this.ChangeTracker 
        .Entries() 
        .Where(p => p.State == System.Data.EntityState.Added 
            p.State == System.Data.EntityState.Deleted    
            p.State == System.Data.EntityState.Modified)) 
    { 
     // For each change record, get the audit record entries and add them 
     foreach (AuditLog log in GetAuditRecordsForChange(ent, userID)) 
     { 
      this.AuditLog.Add(log); 
     } 

    } 

    return base.SaveChanges(); 
} 

的問題是在這(簡稱代碼):

private List<AuditLog> GetAuditRecordsForChange(DbEntityEntry dbEntry, string userID) 
    { 
     if (dbEntry.State == System.Data.EntityState.Modified) 
     { 
      foreach (string propertyName in dbEntry.OriginalValues.PropertyNames) 
      { 
       if (!object.Equals(dbEntry.OriginalValues.GetValue<object>(propertyName), 
        dbEntry.CurrentValues.GetValue<object>(propertyName))) 
       { 
         // It never makes it into this if block, even when 
         // the property has been updated. 
       } 

       // If I updated the property "Name" which was originally "OldName" to the value "NewName" and then break here and inspect the values by calling: 
       //  ?dbEntry.OriginalValues.GetValue<object>("Name").ToString() 

       // the result will be "NewName" and not "OldName" as expected 
      } 
     } 
    } 

奇怪的是,在這種情況下調用dbEntry.Property(propertyName).IsModified();將 返回true。只是這個OriginalValue裏面沒有預期的值。任何人都願意幫助我指出正確的方向嗎?我似乎無法讓這個工作正常。

+0

你是如何查詢你的實體,然後改變屬性值?如果你基本上是附加實體,然後將狀態設置爲修改,那麼原始值將會丟失。要保留原始值,您需要讓EF一直追蹤實體直到保存,否則您需要跟蹤自己代碼中的原始值。 – 2012-03-06 18:11:27

+0

對不起 - 我試圖在評論中發佈一些代碼,但它運行不正常。我正在使用MVC控制器的[HttpPost]動作。這會調用我的產品存儲庫的「SaveProduct」方法。在存儲庫中,它看起來確實調用了'context.Entry(product).State = EntityState.Modified',然後我在上下文中調用SaveChanges。 你能指點我的任何資源來展示你提到的兩種技術嗎?或者至少給我幾個指點? – 2012-03-06 18:25:40

+0

我在MVC中建議使用隱藏字段。基本上你會將你關心的原始值保存到隱藏的字段中,然後在POST中將它們讀回來。我不知道這方面的最佳做法,或者是否有MVC抽象幫助。 – 2012-03-06 18:40:32

回答

11

當EF從數據庫中檢索實體時,它會爲該實體的所有屬性獲取原始值的快照。之後,隨着對這些屬性值的更改,原始值將保持不變,而當前值會更改。

但是,要發生這種情況,EF需要在整個過程中跟蹤實體。在Web或其他n層應用程序中,通常將值發送到客戶端,並且處理用於查詢實體的上下文。這意味着該實體現在不再被EF跟蹤。這是很好的做法。

一旦應用程序回傳實體使用來自客戶端的值重建,然後重新附加到上下文並設置爲修改狀態。但是,默認情況下,客戶端返回的唯一值是當前值。原始值丟失。通常情況下,這並不重要,除非您正在進行樂觀併發或者只想更新真正更改的值。在這些情況下,原始值也應該發送給客戶端(通常作爲Web應用程序中的隱藏字段),然後作爲附加過程的一部分重新應用爲原始值。這在上面的例子中沒有發生,這就是爲什麼原始值沒有按預期顯示。

+0

再次感謝您的幫助。我已經按預期工作了......我想。只是澄清:你是說調用** context.Entry(product).State = EntityState.Modified **重新附加'產品'的上下文,因此它失去了它的OriginalValues跟蹤?此外,[這裏](http://stackoverflow.com/questions/9591165/ef-4-how-to-properly-update-object-in-dbcontext-using-mvc-with-repository-patte)是新帖子我爲我的跟進做了準備(僅供其他人蔘考)。 – 2012-03-06 21:15:20

+0

但是爲什麼該方法在@JoeDePung問題中鏈接到更改跟蹤示例中? – Jensen 2015-11-23 12:36:27

13

如果更改

dbEntry.OriginalValues.GetValue<object>(propertyName); 

dbEntry.GetDatabaseValues().GetValue<object>(propertyName); 

那麼有效。

+4

工程,但審計目的可能非常昂貴。 – eoleary 2013-01-31 22:28:42

+1

爲什麼非常膨脹?如果你想知道更改前後的值,你必須查詢數據庫,沒辦法。 – sintetico82 2015-10-08 10:44:05

+0

它的工作原理..但是,第一個不保留原始值的原因是什麼以及爲什麼與當前值相同@eoleary – Abi 2017-05-31 08:46:56

相關問題