2011-08-11 31 views
5

Tôi đang viết một đường mòn kiểm tra từ các đoạn mã được tìm thấy trực tuyến. Trong khi gọi hàm SaveChanges, tôi lặp lại tất cả các thực thể đã sửa đổi đã đăng ký với Context và xây dựng các mục nhật ký từ các thay đổi của chúng.DbEntityEntry.OriginalValues ​​không điền các thuộc tính phức tạp

foreach (DbEntityEntry modifiedEntity 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 changed record, get the audit record entries and add them 
      foreach(AuditLog x in GetAuditRecordsForChange(modifiedEntity, userId)) 
      { 
       this.AuditLog.Add(x); 
      } 
     } 

Khi tôi sau đó cố gắng truy cập vào các giá trị ban đầu của đơn vị sửa đổi, tất cả các thuộc tính vô hướng được dân cư nhưng những cái phức tạp không tồn tại (số bất động sản sẽ được nói 6 thay vì 8). Sau đó tôi gọi ToObject() để xây dựng đối tượng ở trạng thái ban đầu của nó nhưng rõ ràng các thuộc tính phức tạp là tất cả các giá trị rỗng.

modifiedEntity.OriginalValues.ToObject() 

này chỉ xảy ra với một số của các đối tượng tên miền của tôi, và những đối tượng luôn hiển thị như các proxy sau khi ToObject() cuộc gọi trong khi (tôi không chắc chắn lý do tại sao) nhưng những người mà không có proxy tạo ra cho chúng theo thực thể, các thuộc tính phức tạp của chúng cư trú tốt. Khi tôi sử dụng các proxy POCO như bình thường trong suốt ứng dụng của tôi, tải chậm hoạt động tốt trên chúng.

Tôi nhận thấy rằng nếu tôi thực hiện thay đổi đối với một trong những thuộc tính phức tạp này không được điền như một phần của dữ liệu OriginalValues, trạng thái của đối tượng sẽ không bị thay đổi thành Đã sửa đổi, điều này có ý nghĩa như theo dõi thay đổi so sánh giá trị ban đầu đến hiện tại để xem liệu giá trị đó có thay đổi hay không. Điều gì không có ý nghĩa là dữ liệu vẫn còn tồn tại trên SaveChanged ??

EDIT: Tôi vừa nhận thấy, đối tượng mô hình hiện điền các thuộc tính phức tạp của nó, thuộc tính phức tạp được đề cập (theo quy ước) được coi là 'loại phức' của Thực thể không có khóa chính.

Bất kỳ ý tưởng nào?

Trả lời

4

Tôi tin rằng bài viết này có thể cung cấp cho bạn một số thông tin chi tiết. Nó không phải là EF 4.1 nhưng nhiều lời khuyên và ví dụ được áp dụng.

Complex Types and the New Change Tracking API

của nó một chút trước khi nửa chừng các hướng dẫn với tiêu đề của bộ phận là tên của liên kết. Về cơ bản để truy cập các giá trị ban đầu với kiểu phức tạp, bạn thêm một hàm bổ sung xác định thuộc tính phức tạp.

var original = modifiedEntity.ComplexProperty(u => u.Address).OriginalValues 
+0

Tôi không chắc chắn làm thế nào tôi có thể xây dựng một đường mòn kiểm toán hiệu quả nếu đây là trường hợp. Nếu tôi sửa đổi một thuộc tính phức tạp của một thực thể abitrary tức là 'myVehicle.Colour = myRepo.GetModelById (4)' thì thực thể myVehicle không có trạng thái được thiết lập là MODIFIED. Phải có cách để tìm sự thay đổi này. Tôi đặt câu hỏi về việc sử dụng myEntity.OriginalValues.ToObject() nếu nó xây dựng một đối tượng chỉ với các giá trị vô hướng được điền. Tôi đang thiếu gì? – SeeNoWeevil

+0

Sau một chút đào, có vẻ như những gì tôi đang đề cập đến là theo dõi mối quan hệ, tức là nếu tôi cập nhật tham chiếu trong một thuộc tính của đối tượng cha mẹ của tôi với một đối tượng con khác. Giả sử thuộc tính này trỏ đến một loại thực tế có ID và không phải là 'loại phức tạp' ID, đây là thay đổi _relationship_ và không phải là thay đổi thuộc tính thông thường. Cách duy nhất tôi có thể truy cập vào những thay đổi quan hệ này là thông qua myObjectContext.ObjectStateManager.GetObjectStateEntries (..) Không chắc chắn cách tôi báo cáo chúng hiệu quả như nhật ký kiểm tra. – SeeNoWeevil

1

More đào, có vẻ như EF thay đổi theo dõi không lưu trữ bất kỳ loại giá trị ban đầu để tham khảo hoặc bộ sưu tập thuộc tính loại trên thực thể sửa đổi (một ai đó hãy sửa lại cho tôi nếu tôi sai)

tôi có thể tìm ra ví dụ rằng thực thể Vehicle của tôi có tham chiếu đến một đối tượng VehicleColour bị loại bỏ và sau đó thêm lại trỏ đến một trường hợp khác của VehicleColour. Tôi không thể tìm ra ví dụ rằng nó đã trỏ đến một VehicleColour với một tên "Stardust bạc" và bây giờ chỉ vào một với "Azure Blue".

8

Để nhận tất cả tên thành viên của một thực thể chứ không chỉ các thuộc tính đơn giản mà bạn có thể làm việc với ObjectContext thay vì DbContext, sau đó truy cập danh sách thành viên thông qua EntityType.

((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(dbEntry).EntitySet.ElementType.Members 

Sau đó, bạn có thể sử dụng phương pháp DbEntityEntry.Member(string propertyName) để nhận DbMemberEntry.

Nhận đối tượng đại diện cho thành viên của tổ chức. Kiểu thời gian chạy của đối tượng được trả về sẽ khác nhau tùy thuộc vào loại thành viên được yêu cầu. Các kiểu thành viên hiện được hỗ trợ và kiểu trả về của chúng là thuộc tính dẫn hướng tham chiếu (DbReferenceEntry), thuộc tính điều hướng bộ sưu tập (DbCollectionEntry), thuộc tính nguyên thủy/vô hướng (DbPropertyEntry) và thuộc tính phức tạp (DbComplexPropertyEntry).

Mẫu mã bên dưới sử dụng điều này để ghi nhật ký sửa đổi thuộc tính phức tạp. Lưu ý rằng có thể có điều gì đó hấp dẫn hơn khi ghi lại các thay đổi thuộc tính phức tạp --- Tôi hiện đang ghi toàn bộ thuộc tính phức tạp (được tuần tự hóa thành JSON) thay vì chỉ các thuộc tính bên trong đã thay đổi, nhưng nó hoàn thành công việc.

private IEnumerable<AuditLogEntry> GetAuditLogEntries(DbEntityEntry dbEntry) 
{ 
    if (dbEntry.State == EntityState.Added) 
    { 
     return new AuditLogEntry { ... }; 
    } 

    if (dbEntry.State == EntityState.Deleted) 
    { 
     return new AuditLogEntry { ... }; 
    } 

    if (dbEntry.State == EntityState.Modified) 
    { 
     // Create one AuditLogEntry per updated field. 

     var list = new List<AuditLogEntry>(); 

     // We need to object state entry to do deeper things. 
     ObjectStateEntry objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(dbEntry); 

     // Iterate over the members (i.e. properties (including complex properties), references, collections) of the entity type 
     foreach (EdmMember member in ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(dbEntry).EntitySet.ElementType.Members) 
     { 
      var dbMemberEntry = dbEntry.Member(member.Name) as DbPropertyEntry; 
      if (dbMemberEntry == null || Equals(dbMemberEntry.OriginalValue, dbMemberEntry.CurrentValue)) 
      { 
       // Member entry isn't a property entry or it isn't modified. 
       continue; 
      } 

      string oldValue; 
      string newValue; 

      if (dbMemberEntry is DbComplexPropertyEntry) 
      { 
       // Bit a bit lazy here and just serialise the complex property to JSON rather than detect which inner properties have changed. 
       var complexProperty = (DbComplexPropertyEntry)dbMemberEntry; 
       oldValue = EntitySerialiser.Serialise(complexProperty.OriginalValue as IAuditableComplexType); 
       newValue = EntitySerialiser.Serialise(complexProperty.CurrentValue as IAuditableComplexType); 
      } 
      else 
      { 
       // It's just a plain property, get the old and new values. 
       var property = dbMemberEntry; 
       oldValue = property.OriginalValue.ToStringOrNull(); 
       newValue = property.CurrentValue.ToStringOrNull(); 
      } 

       list.Add(new AuditLogEntry 
         { 
          ..., 
          EventType = AuditEventType.Update, 
          ColumnName = member.Name, 
          OriginalValue = oldValue, 
          NewValue = newValue 
         }); 
     } 

     return list; 
    } 

    // Otherwise empty. 
    return Enumerable.Empty<AuditLogEntry>(); 
} 

Tôi rất mong được thấy các giải pháp khác cho vấn đề này.

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