private void WriteKeys(AuditEntryState state) { var keys = state.EntityType.KeyMembers; if (keys == null) { return; } var currentValues = state.IsDeleted ? state.ObjectStateEntry.OriginalValues : state.ObjectStateEntry.CurrentValues; foreach (var keyMember in keys) { var auditkey = new AuditKey(); try { var name = keyMember.Name; auditkey.Name = name; auditkey.Type = GetType(keyMember); var value = currentValues.GetValue(name); value = FormatValue(state, name, value); auditkey.Value = value; } catch (Exception ex) { Trace.TraceError(ex.Message); auditkey.Value = _errorText; } state.AuditEntity.Keys.Add(auditkey); } }
/// <summary> /// Updates the <see cref="AuditLog" /> from the current <see cref="ObjectContext" /> changes. /// </summary> /// <param name="auditLog">The audit log.</param> /// <returns></returns> public AuditLog UpdateLog(AuditLog auditLog) { if (auditLog == null) { throw new ArgumentNullException("auditLog"); } // must call to make sure changes are detected ObjectContext.DetectChanges(); var entityState = EntityState.Modified; if (Configuration.IncludeInserts) { entityState = entityState | EntityState.Added; } if (Configuration.IncludeDeletes) { entityState = entityState | EntityState.Deleted; } var changes = ObjectContext .ObjectStateManager .GetObjectStateEntries(entityState); foreach (var objectStateEntry in changes) { if (objectStateEntry.Entity == null) { continue; } var entityType = objectStateEntry.Entity.GetType(); entityType = ObjectContext.GetObjectType(entityType); if (!Configuration.IsAuditable(entityType)) { continue; } var state = new AuditEntryState(ObjectContext, objectStateEntry) { AuditLog = auditLog }; if (WriteEntity(state)) { auditLog.Entities.Add(state.AuditEntity); } } return(auditLog); }
private bool WriteEntity(AuditEntryState state) { if (state.EntityType == null) { return(false); } WriteKeys(state); WriteProperties(state); WriteRelationships(state); return(true); }
private static bool IsLoaded(AuditEntryState state, NavigationProperty navigationProperty, IMemberAccessor accessor) { var relationshipManager = state.ObjectStateEntry.RelationshipManager; var getEntityReference = _relatedAccessor.Value.MakeGenericMethod(accessor.MemberType); var parameters = new[] { navigationProperty.RelationshipType.FullName, navigationProperty.ToEndMember.Name }; var entityReference = getEntityReference.Invoke(relationshipManager, parameters) as EntityReference; return(entityReference != null && entityReference.IsLoaded); }
private object FormatValue(AuditEntryState state, string name, object value) { if (value == null) { return(null); } var valueType = value.GetType(); try { var returnValue = valueType.IsEnum ? Enum.GetName(valueType, value) : value; var formatMethod = Configuration.GetFormatter(state.ObjectType, name); if (formatMethod == null) { return(returnValue); } var context = new AuditPropertyContext { ValueType = valueType, Entity = state.Entity, Value = returnValue }; try { return(formatMethod.Invoke(null, context)); } catch { // eat format error? return(returnValue); } } catch (Exception ex) { Trace.TraceError(ex.Message); return(_errorText); } }
private static object GetDisplayValue(AuditEntryState state, NavigationProperty navigationProperty, IMemberAccessor displayMember, DbDataRecord values) { if (values == null) { return(null); } var association = navigationProperty.RelationshipType as AssociationType; if (association == null) { return(null); } // only support first constraint var referentialConstraint = association.ReferentialConstraints.FirstOrDefault(); if (referentialConstraint == null) { return(null); } var toProperties = referentialConstraint .ToProperties .Select(p => p.Name) .ToList(); var fromProperties = referentialConstraint .FromProperties .Select(p => p.Name) .ToList(); // make sure key columns match if (fromProperties.Count != toProperties.Count) { return(null); } var edmType = referentialConstraint .FromProperties .Select(p => p.DeclaringType) .FirstOrDefault(); if (edmType == null) { return(null); } var entitySet = state.ObjectContext.GetEntitySet(edmType.FullName); var sql = new StringBuilder(); sql.Append("SELECT VALUE t.") .Append(displayMember.Name) .Append(" FROM ") .Append(entitySet.Name) .Append(" as t") .Append(" WHERE "); var parameters = new List <ObjectParameter>(); for (var index = 0; index < fromProperties.Count; index++) { if (index > 0) { sql.Append(" AND "); } var fromProperty = fromProperties[index]; var toProperty = toProperties[index]; var value = values.GetValue(toProperty); var name = "@" + fromProperty; sql.Append(" t.").Append(fromProperty); if (value != null) { sql.Append(" == ").Append(name); parameters.Add(new ObjectParameter(fromProperty, value)); } else { sql.Append(" is null"); } } var q = state.ObjectContext.CreateQuery <object>( sql.ToString(), parameters.ToArray()); return(q.FirstOrDefault()); }
private void WriteRelationships(AuditEntryState state) { if (!Configuration.IncludeRelationships) { return; } var properties = state.EntityType.NavigationProperties; if (properties.Count == 0) { return; } var modifiedMembers = state.ObjectStateEntry .GetModifiedProperties() .ToList(); var type = state.ObjectType; var currentValues = state.IsDeleted ? state.ObjectStateEntry.OriginalValues : state.ObjectStateEntry.CurrentValues; var originalValues = state.IsModified ? state.ObjectStateEntry.OriginalValues : null; foreach (var navigationProperty in properties) { if (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many || navigationProperty.FromEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many) { continue; } var name = navigationProperty.Name; if (Configuration.IsNotAudited(type, name)) { continue; } var accessor = state.EntityAccessor.Find(name); var displayMember = Configuration.GetDisplayMember(accessor.MemberType); if (displayMember == null) { continue; // no display property, skip } var isModified = IsModifed(navigationProperty, modifiedMembers); if (state.IsModified && !isModified && !Configuration.IsAlwaysAudited(type, name)) { continue; // this means the property was not changed, skip it } var isLoaded = IsLoaded(state, navigationProperty, accessor); if (!isLoaded && !Configuration.LoadRelationships) { continue; } var auditProperty = new AuditProperty(); try { auditProperty.Name = name; auditProperty.Type = accessor.MemberType.FullName; auditProperty.IsRelationship = true; auditProperty.ForeignKey = GetForeignKey(navigationProperty); object currentValue = null; if (isLoaded) { // get value directly from instance to save db call var valueInstance = accessor.GetValue(state.Entity); if (valueInstance != null) { currentValue = displayMember.GetValue(valueInstance); } } else { // get value from db currentValue = GetDisplayValue(state, navigationProperty, displayMember, currentValues); } // format currentValue = FormatValue(state, name, currentValue); if (!state.IsModified && currentValue == null) { continue; // skip null value } switch (state.AuditEntity.Action) { case AuditAction.Added: auditProperty.Current = currentValue; break; case AuditAction.Modified: auditProperty.Current = currentValue ?? _nullText; if (Configuration.LoadRelationships) { var originalValue = GetDisplayValue(state, navigationProperty, displayMember, originalValues); originalValue = FormatValue(state, name, originalValue); auditProperty.Original = originalValue; } break; case AuditAction.Deleted: auditProperty.Original = currentValue; break; } } catch (Exception ex) { Trace.TraceError(ex.Message); if (state.IsDeleted) { auditProperty.Original = _errorText; } else { auditProperty.Current = _errorText; } } state.AuditEntity.Properties.Add(auditProperty); } }
private void WriteProperties(AuditEntryState state) { var properties = state.EntityType.Properties; if (properties == null) { return; } var modifiedMembers = state.ObjectStateEntry .GetModifiedProperties() .ToList(); var type = state.ObjectType; var currentValues = state.IsDeleted ? state.ObjectStateEntry.OriginalValues : state.ObjectStateEntry.CurrentValues; var originalValues = state.IsModified ? state.ObjectStateEntry.OriginalValues : null; foreach (var edmProperty in properties) { var name = edmProperty.Name; if (Configuration.IsNotAudited(type, name)) { continue; } var isModified = modifiedMembers.Any(m => m == name); if (state.IsModified && !isModified && !Configuration.IsAlwaysAudited(type, name)) { continue; // this means the property was not changed, skip it } var auditProperty = new AuditProperty(); try { auditProperty.Name = name; auditProperty.Type = GetType(edmProperty); var currentValue = currentValues.GetValue(name); currentValue = FormatValue(state, name, currentValue); if (!state.IsModified && currentValue == null) { continue; // ignore null properties? } switch (state.AuditEntity.Action) { case AuditAction.Added: auditProperty.Current = currentValue; break; case AuditAction.Modified: auditProperty.Current = currentValue; if (originalValues != null) { var originalValue = originalValues.GetValue(edmProperty.Name); originalValue = FormatValue(state, name, originalValue); auditProperty.Original = originalValue; } break; case AuditAction.Deleted: auditProperty.Original = currentValue; break; } } catch (Exception ex) { Trace.TraceError(ex.Message); if (state.IsDeleted) { auditProperty.Original = _errorText; } else { auditProperty.Current = _errorText; } } state.AuditEntity.Properties.Add(auditProperty); } // foreach property }