/// <summary> /// Ensures the automatic history. /// </summary> /// <param name="context">The context.</param> public static void EnsureAutoHistory(this DbContext context) { // TODO: only record the changed properties. var jsonSetting = new JsonSerializerSettings { ContractResolver = new EntityContractResolver(context), }; var entries = context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged && e.State != EntityState.Detached && IncludeEntity(e)).ToList(); if (entries.Count == 0) { return; } foreach (var entry in entries) { var history = new AutoHistory { TypeName = entry.Entity.GetType().FullName, }; switch (entry.State) { case EntityState.Added: // REVIEW: what's the best way to do this? history.SourceId = "0"; history.Kind = EntityState.Added; history.AfterJson = JsonConvert.SerializeObject(entry.Entity, Formatting.Indented, jsonSetting); break; case EntityState.Deleted: history.SourceId = entry.PrimaryKey(); history.Kind = EntityState.Deleted; history.BeforeJson = JsonConvert.SerializeObject(entry.Entity, Formatting.Indented, jsonSetting); break; case EntityState.Modified: history.SourceId = entry.PrimaryKey(); history.Kind = EntityState.Modified; history.BeforeJson = JsonConvert.SerializeObject(entry.Original(), Formatting.Indented, jsonSetting); history.AfterJson = JsonConvert.SerializeObject(entry.Entity, Formatting.Indented, jsonSetting); break; default: continue; } context.Add(history); } }
internal static AutoHistory AutoHistory(this EntityEntry entry) { var history = new AutoHistory { TableName = entry.Metadata.Relational().TableName, }; // Get the mapped properties for the entity type. // (include shadow properties, not include navigations & references) var properties = entry.Properties; var json = new JObject(); switch (entry.State) { case EntityState.Added: foreach (var prop in properties) { if (prop.Metadata.IsKey() || prop.Metadata.IsForeignKey()) { continue; } json[prop.Metadata.Name] = prop.CurrentValue != null ? JToken.FromObject(prop.CurrentValue, _jsonerializer) : JValue.CreateNull(); } // REVIEW: what's the best way to set the RowId? history.RowId = "0"; history.Kind = EntityState.Added; history.Changed = json.ToString(); break; case EntityState.Modified: var bef = new JObject(); var aft = new JObject(); foreach (var prop in properties) { if (prop.IsModified) { bef[prop.Metadata.Name] = prop.OriginalValue != null ? JToken.FromObject(prop.OriginalValue, _jsonerializer) : JValue.CreateNull(); aft[prop.Metadata.Name] = prop.CurrentValue != null ? JToken.FromObject(prop.CurrentValue, _jsonerializer) : JValue.CreateNull(); } } json["before"] = bef; json["after"] = aft; history.RowId = entry.PrimaryKey(); history.Kind = EntityState.Modified; history.Changed = json.ToString(); break; case EntityState.Deleted: foreach (var prop in properties) { json[prop.Metadata.Name] = prop.OriginalValue != null ? JToken.FromObject(prop.OriginalValue, _jsonerializer) : JValue.CreateNull(); } history.RowId = entry.PrimaryKey(); history.Kind = EntityState.Deleted; history.Changed = json.ToString(); break; case EntityState.Detached: case EntityState.Unchanged: default: throw new NotSupportedException("AutoHistory only support Deleted and Modified entity."); } return(history); }