/// <summary> /// Creates an audit log entry for a <see cref="DbEntityEntry"/> that has an <see cref="EntityState"/> of <see cref="EntityState.Added"/> or <see cref="EntityState.Modified"/> /// It will create an audit log entry for each property that has changed /// </summary> private static AuditLog CreateAuditLogEntryForAddedOrModified(ObjectContext objectContext, DbEntityEntry dbEntry, string tableName, Person person, DateTime changeDate, AuditLogEventType auditLogEventType, DbPropertyEntry modifiedProperty) { var propertyName = modifiedProperty.Name; if (!string.Equals(propertyName, $"{tableName}ID", StringComparison.InvariantCultureIgnoreCase) && !string.Equals(propertyName, "TenantID", StringComparison.InvariantCultureIgnoreCase)) { var optionalAuditDescriptionString = GetAuditDescriptionStringIfAnyForProperty(objectContext, dbEntry, propertyName, auditLogEventType); var auditLogEntry = CreateAuditLogEntryImpl(dbEntry, tableName, person, changeDate, auditLogEventType, propertyName, modifiedProperty.CurrentValue, modifiedProperty.OriginalValue, optionalAuditDescriptionString); return(auditLogEntry); } return(null); }
/// <summary> /// Enum types are equal by primary key /// </summary> public bool Equals(AuditLogEventType other) { if (other == null) { return(false); } return(other.AuditLogEventTypeID == AuditLogEventTypeID); }
public string GetAuditDescriptionDisplay() { if (string.IsNullOrWhiteSpace(AuditDescription)) { return(AuditLogEventType.GetAuditStringForOperationType(ColumnName, OriginalValue, NewValue)); } return(AuditDescription); }
/// <summary> /// Constructor for building a new object with MinimalConstructor required fields, using objects whenever possible /// </summary> public AuditLog(Person person, DateTime auditLogDate, AuditLogEventType auditLogEventType, string tableName, int recordID, string columnName, string newValue) : this() { // Mark this as a new object by setting primary key with special value this.AuditLogID = ModelObjectHelpers.MakeNextUnsavedPrimaryKeyValue(); this.PersonID = person.PersonID; this.Person = person; person.AuditLogs.Add(this); this.AuditLogDate = auditLogDate; this.AuditLogEventTypeID = auditLogEventType.AuditLogEventTypeID; this.TableName = tableName; this.RecordID = recordID; this.ColumnName = columnName; this.NewValue = newValue; }
/// <summary> /// Creates an audit log entry for a <see cref="DbEntityEntry"/> that has an <see cref="EntityState"/> of <see cref="EntityState.Deleted"/> /// Deleted log entries do not have columns/property names, so there will just be one record created /// </summary> private static AuditLog CreateAuditLogEntryForDeleted(DbEntityEntry dbEntry, string tableName, Person person, DateTime changeDate, AuditLogEventType auditLogEventType) { var auditableEntityDeleted = GetIAuditableEntityFromEntity(dbEntry.Entity, tableName); var optionalAuditDescriptionString = auditLogEventType.GetAuditStringForOperationType(tableName, null, auditableEntityDeleted.GetAuditDescriptionString()); var auditLogEntry = CreateAuditLogEntryImpl(dbEntry, tableName, person, changeDate, auditLogEventType, "*ALL", AuditLogEventType.Deleted.AuditLogEventTypeDisplayName, null, optionalAuditDescriptionString); return(auditLogEntry); }
private static AuditLog CreateAuditLogEntryImpl(DbEntityEntry dbEntry, string tableName, Person person, DateTime changeDate, AuditLogEventType auditLogEventType, string propertyName, object newValue, object originalValue, string optionalAuditDescriptionString) { var recordID = (int)dbEntry.Property(PrimaryKeyName).CurrentValue; var newValueString = newValue != null?newValue.ToString() : string.Empty; var auditLog = new AuditLog(person, changeDate, auditLogEventType, tableName, recordID, propertyName, newValueString) { OriginalValue = originalValue?.ToString(), AuditDescription = optionalAuditDescriptionString }; return(auditLog); }
/// <summary> /// Gets the audit description string for a property that came from a <see cref="DbEntityEntry"/> that has an <see cref="EntityState"/> of <see cref="EntityState.Added"/> or <see cref="EntityState.Modified"/> /// This will attempt to look up a foreign key and return a more descriptive string for that fk property /// </summary> public static string GetAuditDescriptionStringIfAnyForProperty(ObjectContext objectContext, DbEntityEntry dbEntry, string propertyName, AuditLogEventType auditLogEventType) { var objectStateEntry = objectContext.ObjectStateManager.GetObjectStateEntry(dbEntry.Entity); // find foreign key relationships for given propertyname var relatedEnds = GetDependentForeignKeyRelatedEndsForProperty(objectStateEntry, propertyName); foreach (var end in relatedEnds) { if (!(end.RelationshipSet.ElementType is AssociationType elementType) || !elementType.IsForeignKey) { continue; } foreach (var constraint in elementType.ReferentialConstraints) { // Multiplicity many means we are looking at a foreign key in a dependent entity // I assume that ToRole will point to a dependent entity, don't know if it can be FromRole Check.Require(constraint.ToRole.RelationshipMultiplicity == RelationshipMultiplicity.Many); // If not 1 then it is a composite key I guess. Becomes a lot more difficult to handle. Check.Require(constraint.ToProperties.Count == 1); var entityName = constraint.FromRole.Name; string auditDescriptionStringForOriginalValue = null; if (!IgnoredTables.Contains(entityName)) { var constraintProperty = constraint.ToProperties[0]; var principalEntity = (EntityReference)end; var newEntityKey = principalEntity.EntityKey; var auditDescriptionStringForNewValue = GetAuditDescriptionStringForEntityKey(objectContext, newEntityKey, entityName); if (newEntityKey != null) { var oldEntityKey = CreateEntityKeyForValue(newEntityKey.EntitySetName, principalEntity.EntityKey.EntityKeyValues[0].Key, objectStateEntry.OriginalValues[constraintProperty.Name]); auditDescriptionStringForOriginalValue = GetAuditDescriptionStringForEntityKey(objectContext, oldEntityKey, entityName); } return(auditLogEventType.GetAuditStringForOperationType(entityName, auditDescriptionStringForOriginalValue, auditDescriptionStringForNewValue)); } } } return(null); }
/// <summary> /// Creates a "blank" object of this type and populates primitives with defaults /// </summary> public static AuditLog CreateNewBlank(Person person, AuditLogEventType auditLogEventType) { return(new AuditLog(person, default(DateTime), auditLogEventType, default(string), default(int), default(string), default(string))); }