2012-03-06 37 views
6

Tôi cố gắng để thực hiện một AuditLog sử dụng EF 4.1, bằng cách ghi đè các SaveChanges() phương pháp như đã trình bày ở các vị trí sau:Entity Framework DbContext SaveChanges() OriginalValue sai

Tôi đang gặp sự cố với mục nhập "đã sửa đổi". Bất cứ khi nào tôi cố gắng truy cập vào số OriginalValue của thuộc tính được đề cập, giá trị này luôn có giá trị giống như trong trường CurrentValue.

đầu tiên tôi sử dụng mã này, và nó xác định thành công mục dữ liệu nào được sửa đổi:

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(); 
} 

Vấn đề là trong này (mã viết tắt):

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 
      } 
     } 
    } 

Điều kỳ lạ là các hãy gọi tới số dbEntry.Property(propertyName).IsModified(); sẽ trả lại đúng trong trường hợp này. Nó chỉ là OriginalValue không có giá trị kỳ vọng bên trong. Có ai sẵn lòng giúp tôi đi đúng hướng không? Tôi dường như không thể làm điều này để hoạt động chính xác.

+0

Bạn truy vấn các thực thể của mình như thế nào và sau đó thay đổi các giá trị thuộc tính? Nếu bạn về cơ bản gắn thực thể và sau đó thiết lập trạng thái để sửa đổi, sau đó các giá trị ban đầu sẽ bị mất. Để giữ các giá trị ban đầu, bạn cần phải theo dõi EF thực thể tất cả các cách từ truy vấn cho đến khi lưu, hoặc bạn cần phải theo dõi các giá trị ban đầu trong mã của riêng bạn. –

+0

Xin lỗi - Tôi đã cố gắng đăng một số mã trong các nhận xét nhưng nó không hoạt động tốt.Tôi đang sử dụng một hành động [HttpPost] của một bộ điều khiển MVC. Điều này gọi phương thức "SaveProduct" của kho lưu trữ sản phẩm của tôi. Trong kho lưu trữ có vẻ như tôi thực sự gọi 'context.Entry (sản phẩm) .State = EntityState.Modified' và sau đó tôi SaveChanges trên ngữ cảnh. Bạn có thể chỉ cho tôi bất kỳ tài nguyên nào thể hiện hai kỹ thuật bạn đã đề cập không? Hoặc ít nhất là cho tôi một vài gợi ý? –

+0

Tôi _think_ trong MVC cách được khuyến nghị để làm điều này sẽ là với các trường ẩn. Về cơ bản bạn sẽ lưu các giá trị ban đầu mà bạn quan tâm vào các trường ẩn và sau đó đọc lại chúng trong POST của bạn. Tôi không biết thực hành tốt nhất xung quanh điều này hoặc nếu có một sự trừu tượng MVC để giúp đỡ. –

Trả lời

11

Khi EF truy xuất thực thể từ cơ sở dữ liệu, nó sẽ chụp nhanh các giá trị ban đầu cho tất cả các thuộc tính của thực thể đó. Sau đó, khi các thay đổi được thực hiện cho các giá trị của các thuộc tính này, các giá trị ban đầu sẽ vẫn giữ nguyên trong khi các giá trị hiện tại thay đổi.

Tuy nhiên, để điều này xảy ra, EF cần phải theo dõi thực thể trong suốt quá trình. Trong một ứng dụng web hoặc n-tier khác, thông thường các giá trị được gửi tới máy khách và ngữ cảnh được sử dụng để truy vấn thực thể được xử lý. Điều này có nghĩa là thực thể hiện không còn được theo dõi bởi EF nữa. Điều này là tốt và thực hành tốt.

Khi ứng dụng đăng lại thực thể được xây dựng lại bằng các giá trị từ máy khách và sau đó được đính kèm lại vào ngữ cảnh và được đặt thành trạng thái Đã sửa đổi. Tuy nhiên, theo mặc định, các giá trị duy nhất quay lại từ máy khách là các giá trị hiện tại. Các giá trị ban đầu bị mất. Thông thường điều này không quan trọng trừ khi bạn đang làm đồng thời lạc quan hoặc muốn rất cẩn thận về chỉ cập nhật các giá trị đã thực sự thay đổi. Trong những trường hợp này, các giá trị gốc cũng phải được gửi tới máy khách (thường là các trường ẩn trong ứng dụng web) và sau đó được áp dụng lại làm giá trị ban đầu như một phần của quy trình đính kèm. Điều này đã không xảy ra trong ví dụ trên và đây là lý do tại sao các giá trị ban đầu không hiển thị như mong đợi.

+0

Cảm ơn bạn một lần nữa vì đã giúp đỡ. Tôi đã có nó làm việc như mong đợi bây giờ ... Tôi nghĩ vậy. Chỉ cần làm rõ: Bạn có nói rằng ** gọi context.Entry (sản phẩm) .State = EntityState.Modified ** lại gắn 'sản phẩm' vào bối cảnh và do đó nó mất theo dõi của OriginalValues ​​của nó? Ngoài ra, [ở đây] (http://stackoverflow.com/questions/9591165/ef-4-how-to-properly-update-object-in-dbcontext-using-mvc-with-repository-patte) là bài đăng mới Tôi đã thực hiện cho theo dõi của tôi (chỉ để tham khảo cho người khác). –

+0

Nhưng tại sao phương pháp làm việc trong Ví dụ theo dõi thay đổi được liên kết trong câu hỏi @JoeDePung? – Jensen

13

Nếu bạn thay đổi

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

để

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

sau đó làm việc.

+4

Hoạt động, nhưng có lẽ rất tốn kém cho mục đích kiểm toán. – eoleary

+1

Tại sao rất rộng? Nếu bạn muốn biết giá trị trước và sau khi thay đổi bạn phải truy vấn cơ sở dữ liệu, không có cách nào. – sintetico82

+0

nó hoạt động .. nhưng lý do đầu tiên không giữ giá trị ban đầu là gì và tại sao giống như currentvalue @eoleary – Abi

Các vấn đề liên quan