Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public interface IAuditChangesDetector {
- AuditInfo[] Detect();
- AuditInfo[] PostProcess(AuditInfo[] info);
- }
- public class AuditInfo {
- public Guid AuditSetId { get; set; }
- public DateTime AuditDateTime { get; set; }
- public string ExecutedByUser { get; set; }
- public string ActionType { get; set; }
- public string Entity { get; set; }
- public string EntityKey { get; set; }
- public AuditPropertyInfo[] Properties { get; set; }
- }
- public class AuditPropertyInfo {
- public string Property { get; set; }
- public string OldValue { get; set; }
- public string NewValue { get; set; }
- }
- public class EfAuditChangesDetector : IAuditChangesDetector {
- public EfAuditChangesDetector(DbContext context) {
- if (context == null)
- throw new ArgumentNullException("context");
- _dbContext = context;
- }
- private readonly DbContext _dbContext;
- private ObjectStateManager _objectStateManager;
- AuditInfo[] IAuditChangesDetector.Detect() {
- if (!(_dbContext is IObjectContextAdapter))
- throw new InvalidOperationException("The context should be an IObjectContextAdapter).");
- var adapter = _dbContext as IObjectContextAdapter;
- if (adapter == null || adapter.ObjectContext == null || adapter.ObjectContext.ObjectStateManager == null)
- throw new InvalidOperationException("The object-state-manager could not be found.");
- _objectStateManager = adapter.ObjectContext.ObjectStateManager;
- var info = new List<AuditInfo>();
- var auditSetId = Guid.NewGuid();
- var auditDateTime = DateTime.Now;
- var executedByUser = "<username>";
- Func<ActionType, EfAuditInfo> createInfo = a => new EfAuditInfo {
- AuditSetId = auditSetId,
- AuditDateTime = auditDateTime,
- ExecutedByUser = executedByUser,
- ActionType = a.ToString(),
- ActionTypeEx = a
- };
- var deletedObjects = FindDeletedObjects(createInfo);
- var modifiedObjects = FindModifiedObjects(createInfo);
- var addedObjects = FindAddedObjects(createInfo);
- return deletedObjects
- .Concat(modifiedObjects)
- .Concat(addedObjects)
- .ToArray();
- }
- private EfAuditInfo[] FindDeletedObjects(Func<ActionType, EfAuditInfo> createInfo) {
- var deletedObjects = _objectStateManager.GetObjectStateEntries(EntityState.Deleted).ToArray();
- var infos = new List<EfAuditInfo>();
- foreach (var deletedObject in deletedObjects) {
- var pks = deletedObject.EntityKey.EntityKeyValues.Select(x => x.Key).ToArray();
- var pkValues = new List<string>();
- var entry = _dbContext.Entry(deletedObject.Entity);
- var audit = createInfo(ActionType.Deleted);
- audit.Entity = deletedObject.EntitySet.Name;
- var auditProperties = new List<AuditPropertyInfo>();
- foreach (var propertyName in entry.OriginalValues.PropertyNames) {
- var oldValue = entry.Property(propertyName).OriginalValue;
- var oldValueString = oldValue != null ? oldValue.ToString() : null;
- var isPk = pks.Contains(propertyName);
- if (isPk) {
- pkValues.Add(oldValueString);
- }
- if (propertyName.ToLower() != "timestamp" && oldValueString != "System.Byte[]") {
- var auditPropertyInfo = new AuditPropertyInfo {
- Property = propertyName,
- OldValue = oldValueString,
- NewValue = oldValueString
- };
- auditProperties.Add(auditPropertyInfo);
- }
- }
- audit.Properties = auditProperties.ToArray();
- audit.EntityKey = string.Join(";", pkValues);
- audit.ObjectStateEntry = deletedObject;
- audit.DbEntityEntry = entry;
- infos.Add(audit);
- }
- return infos.ToArray();
- }
- private EfAuditInfo[] FindModifiedObjects(Func<ActionType, EfAuditInfo> createInfo) {
- var modifiedObjects = _objectStateManager.GetObjectStateEntries(EntityState.Modified).ToList();
- var infos = new List<EfAuditInfo>();
- foreach (var modifiedObject in modifiedObjects) {
- var pks = modifiedObject.EntityKey.EntityKeyValues.Select(x => x.Key).ToList();
- var pkValues = new List<string>();
- var entry = _dbContext.Entry(modifiedObject.Entity);
- var audit = createInfo(ActionType.Modified);
- audit.Entity = modifiedObject.EntitySet.Name;
- var auditProperties = new List<AuditPropertyInfo>();
- foreach (var propertyName in entry.CurrentValues.PropertyNames) {
- var oldValue = entry.Property(propertyName).OriginalValue;
- var oldValueString = oldValue != null ? oldValue.ToString() : null;
- var currentValue = entry.Property(propertyName).CurrentValue;
- var currentValueString = currentValue != null ? currentValue.ToString() : null;
- var isPk = pks.Contains(propertyName);
- if (isPk) {
- pkValues.Add(currentValueString);
- }
- if (propertyName.ToLower() != "timestamp" && oldValueString != "System.Byte[]") {
- // filter out the timestamp column
- if (string.CompareOrdinal(oldValueString, currentValueString) != 0 || isPk) {
- var auditPropertyInfo = new AuditPropertyInfo {
- Property = propertyName,
- OldValue = oldValueString,
- NewValue = currentValueString
- };
- auditProperties.Add(auditPropertyInfo);
- }
- }
- }
- audit.Properties = auditProperties.ToArray();
- audit.EntityKey = string.Join(";", pkValues);
- audit.ObjectStateEntry = modifiedObject;
- audit.DbEntityEntry = entry;
- infos.Add(audit);
- }
- return infos.ToArray();
- }
- private EfAuditInfo[] FindAddedObjects(Func<ActionType, EfAuditInfo> createInfo) {
- var addedObjects = _objectStateManager.GetObjectStateEntries(EntityState.Added).ToList();
- var infos = new List<EfAuditInfo>();
- foreach (var addedObject in addedObjects) {
- var entry = _dbContext.Entry(addedObject.Entity);
- var audit = createInfo(ActionType.Added);
- audit.Entity = addedObject.EntitySet.Name;
- var auditProperties = new List<AuditPropertyInfo>();
- foreach (var propertyName in entry.CurrentValues.PropertyNames) {
- var currentValue = entry.Property(propertyName).CurrentValue;
- var currentValueString = currentValue != null ? currentValue.ToString() : null;
- if (propertyName.ToLower() != "timestamp" && currentValueString != "System.Byte[]") {
- var auditPropertyInfo = new AuditPropertyInfo {
- Property = propertyName,
- NewValue = currentValueString
- };
- auditProperties.Add(auditPropertyInfo);
- }
- }
- audit.Properties = auditProperties.ToArray();
- audit.ObjectStateEntry = addedObject;
- audit.DbEntityEntry = entry;
- infos.Add(audit);
- }
- return infos.ToArray();
- }
- AuditInfo[] IAuditChangesDetector.PostProcess(AuditInfo[] auditInfo) {
- var infos = auditInfo.Cast<EfAuditInfo>()
- .Where(x => x.DbEntityEntry.State != EntityState.Detached)
- .Where(x => x.ActionTypeEx == ActionType.Added || x.ActionTypeEx == ActionType.Modified)
- .ToArray();
- foreach (var info in infos){
- var pks = info.ObjectStateEntry.EntityKey.EntityKeyValues.Select(x => x.Key).ToArray();
- var pkValues = new List<string>();
- foreach (var propertyInfo in info.Properties) {
- // Get new current value for changed properties. Basically this updates the id's with actual values.
- var propertyName = propertyInfo.Property;
- var currentValue = info.DbEntityEntry.Property(propertyName).CurrentValue;
- var currentValueString = currentValue != null ? currentValue.ToString() : null;
- if (info.ActionTypeEx == ActionType.Added || info.ActionTypeEx == ActionType.Modified) {
- propertyInfo.NewValue = currentValueString;
- }
- // Generate single PK value
- var isPk = pks.Contains(propertyName);
- if (isPk) {
- pkValues.Add(currentValueString);
- }
- }
- info.EntityKey = string.Join(";", pkValues);
- }
- return auditInfo;
- }
- private enum ActionType {
- Added,
- Modified,
- Deleted
- }
- private class EfAuditInfo : AuditInfo {
- public DbEntityEntry DbEntityEntry { get; set; }
- public ObjectStateEntry ObjectStateEntry { get; set; }
- public ActionType ActionTypeEx { get; set; }
- }
- }
- // Usage:
- using (var context = someDbContextFactory.Create()) {
- DoLotsOfWorkWithTheContext(context);
- // Create detector
- IAuditChangesDetector detector = new EfAuditChangesDetector(context);
- // Retrieve audit info
- var auditInfo = detector.Detect();
- // Save changes
- context.SaveChanges();
- // Post process audit info to set the inserted id's
- auditInfo = detector.PostProcess(auditInfo);
- // Now you can save the audit info somewhere, in a logfile, a new context, whatever...
- }
Advertisement
Add Comment
Please, Sign In to add comment