ChangeTracker Entity Framework 4.1 - 相關對象的原始值
我有一個我繼承的基類,它與其他實體有兩個零到多關係:
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該關係的實例。這些實例不應該有 stateModified。它們要麼是Added,Deleted要麼Unchanged是因為“修改”被處理為刪除舊關係並添加新關係。ObjectStateEntry還包含CurrentValues和OriginalValues集合。這些集合還應該包含兩個項目,每個項目代表EntityKey關係一側的實體。