Dot-Net

ChangeTracker Entity Framework 4.1 - 相關對象的原始值

  • August 6, 2012

我有一個我繼承的基類,它與其他實體有兩個零到多關係:

public abstract class WebObject
{
   public WebObject()
   {
       RelatedTags = new List<Tag>();
       RelatedWebObjects = new List<WebObject>();
   }

   [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public Guid Id { get; set; }

   public string MetaKeywords { get; set; }
   public string MetaDescription { get; set; }

   [InverseProperty("WebObjects")]
   public virtual WebSite WebSite { get; set; }

   [Required(ErrorMessage = "Every WebObject must be associated with a WebSite.")]
   public Guid WebSiteId { get; set; }

   public virtual ICollection<Tag> RelatedTags { get; set; }
   public IList<Guid> RelatedTagIds { get; set; }
   public virtual ICollection<WebObject> RelatedWebObjects { get; set; }
   public IList<Guid> RelatedWebObjectIds { get; set; }
}

在 SaveChanges 期間查看使用 ChangeTracker 的實體時,我很難獲得這些關係(RelatedWebObjects 和 RelatedTags)的原始值。我可以看到之前和之後的所有標量值,我可以看到新的關係,但我看不到舊的。我試過使用 Member 和 Collection 方法,但那些只顯示目前值;不是舊的。我也不喜歡使用這些,因為它需要我知道導航屬性的名稱,這不夠通用。

我可以找到關係正在改變的相關對象,但是這些相關對像中的值當然沒有改變,所以這也沒有任何幫助。

在使用 ChangeTracker 進行 SaveChanges 期間,我是否有一些乾淨的方法可以跟踪實體的先前關係?

以下是我正在處理的程式碼部分:

   public override int SaveChanges()
   {
       List<AuditObject> auditTrailList = new List<AuditObject>();

       foreach (DbEntityEntry entity in ChangeTracker.Entries().Where(obj => { return obj.State == EntityState.Added || obj.State == EntityState.Modified || obj.State == EntityState.Deleted; }))
       {
           if (!(entity.Entity is AuditObject))
           {
               AuditObject auditObject = new AuditObject();

               auditObject.Id = Guid.NewGuid();

               auditObject.RevisionStamp = DateTime.Now;

               auditObject.UserName = HttpContext.Current.User.Identity.Name;

               auditObject.EntityType = Utilities.GetCleanClassNameIfProxyClass(entity.Entity.GetType().Name);

               if (entity.State == EntityState.Added)
                   auditObject.Action = EntityState.Added.ToString();
               else if (entity.State == EntityState.Modified)
                   auditObject.Action = EntityState.Modified.ToString();
               else if (entity.State == EntityState.Deleted)
                   auditObject.Action = EntityState.Deleted.ToString();

               DbMemberEntry t1 = entity.Member("RelatedWebObjects");
               // cannot find original relationship collection...

               DbCollectionEntry t2 = entity.Collection("RelatedWebObjects");
               // cannot find original relationship collection...

               if (entity.State == EntityState.Added || entity.State == EntityState.Modified)
               {
                   XDocument currentValues = new XDocument(new XElement(auditObject.EntityType));

                   foreach (string propertyName in entity.CurrentValues.PropertyNames)
                   {
                       currentValues.Root.Add(new XElement(propertyName, entity.CurrentValues[propertyName]));
                   }

                   auditObject.NewData = Regex.Replace(currentValues.ToString(), @"\r\n+", " ");
               }

               if (entity.State == EntityState.Modified || entity.State == EntityState.Deleted)
               {
                   XDocument originalValues = new XDocument(new XElement(auditObject.EntityType));

                   foreach (string propertyName in entity.OriginalValues.PropertyNames)
                   {
                       originalValues.Root.Add(new XElement(propertyName, entity.OriginalValues[propertyName]));
                   }

                   auditObject.OldData = Regex.Replace(originalValues.ToString(), @"\r\n+", " ");
               }

               auditTrailList.Add(auditObject);
           }
       }

       foreach (var audit in auditTrailList)
           this.AuditObjects.Add(audit);

       return base.SaveChanges();
   }

因為 EF 更改跟踪圖表中的每個對象,所以您始終可以將圖表中的任何實例傳遞給更改跟踪器,它會為您提供更改跟踪值。例如,以下程式碼將獲取 AuditObject 導航屬性的原始/目前值:

DbMemberEntry t1 = entity.Member("RelatedWebObjects");
// cannot find original relationship collection....

AuditObject currentAuditObject = (AuditObject) entity;
var currValues = this.Entry(currentAuditObject.RelatedWebObjects).CurrentValues;
var orgValues = this.Entry(currentAuditObject.RelatedWebObjects).OriginalValues;

或者,您可以在處理集合類型導航屬性時應用相同的技巧:

DbCollectionEntry t2 = entity.Collection("RelatedWebObjects");
// cannot find original relationship collection....

foreach (WebObject item in currentAuditObject.RelatedWebObjects)
{
   var currValues = this.Entry(item).CurrentValues;
}

嗯,這有點困難。首先,您必須區分 EF 提供的兩種類型的關係:

  • 獨立關聯(所有多對多關係和一些一對多)
  • 外鍵關聯(所有一對一關係和一些一對多)

現在,如果您想知道外鍵關聯的先前值,您只需要跟踪已暴露外鍵屬性的依賴實體中的更改 - 這與跟踪任何其他屬性更改完全相同。

如果您想跟踪獨立關聯中的更改,情況將變得更加困難,因為 DbContext API不提供跟踪它們的操作。您必須恢復到ObjectContextAPI 及其ObjectStateManager.

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
foreach (ObjectStateEntry entry = objectContext.ObjectStateManager
                                              .GetObjectStateEntries(~EntityState.Detached)
                                              .Where(e => e.IsRelationship))
{
   // Track changes here
}

現在您可以訪問ObjectStateEntry該關係的實例。這些實例不應該有 state Modified。它們要麼是AddedDeleted要麼Unchanged是因為“修改”被處理為刪除舊關係並添加新關係。ObjectStateEntry還包含CurrentValuesOriginalValues集合。這些集合還應該包含兩個項目,每個項目代表EntityKey關係一側的實體。

引用自:https://stackoverflow.com/questions/7079228