I think you will need the full-qualified-name of the object's type when desalinizing, so that will be mandatory.
Alternatively serializing the object will be cause you problems.
Assume that we are going to audit TacoOject1 of Taco class using the approch, the serialized data will be put in data base, later due to business changes we need to add another property to Taco, after recompilation when we need to deserilazed TacoOject1 we will get TypeMissMatchException
(not sure of exception name).
Another design objection is using inheritance for audit process.
First: In reality Taco is not a
AuditableObject , Its a roll played by Taco, using inheritance will violate Liskov Substitution Principle.
Second: You can not use multiple inheritance, think that if we had a TacoSupperClass, how we could audit Taco then?
If I where going to design auditing process, I would use Entity–attribute–value model
Making AuditItem
a marker interface and rename it to IAuditableEntity
.
Having an attribute called AuditableProperty
would enhance our process.
Any entity needs to be audited will be marked by IAuditableEntity, any property of the entity needed to be partcipated in audit will be marked by AuditableProperty attribute.
public class Taco : IAuditableEntity
{
[AuditableProperty]
public string Seasoning { get; set; }
[AuditableProperty]
public string OtherProperty1 { get; set; }
public string OtherProperty2 { get; set; }
}
The AuditLog
table will have these columns:
1. EntityFullTypeName
: (String) We are going to audit different entities, the field will be used to get meaningful reports .(mandatory)
2. ObjectIdentifier
: Entity identifier that is being manipulated, primary key or business key of the entity.
3. FieldName
: (String) Entity field name.
4. OldValue
: (String) Entity field old value.
5. NewValue
: (String) Entity field new value.
6. TransactionUser
: Application user that makes the change. (mandatory)
7. TransactionID
: Any operation changing the entities will need to have a unique transaction ID (like GUID) (mandatory), In case of an update on an entity changing multiple fields,these column will be the key point to trace all changes in the update(transcation)
8. ChangeDate
: Transaction date. (mandatory)
9. FieldType
: enumeration or text showing the field type like TEXT or Double. (mandatory)
In service layer when Taco1 is going to be updated(or inserted) we will check if Taco1 type is marked by IAuditableEntity using reflection(using a lazy chash to store reflection data), if so which properties have been changed(we need a separate DB call to fetch old values).
e.g :
Taco1 = new Taco();
Taco1.Seasoning = "old Seasoning value";
Taco1.OtherProperty1 = "Old Other Property1 value";
Taco1.OtherProperty2 = "Old Other Property2 value";
Saved before,now updating:
Taco1.Seasoning = "New Seasoning value";
Taco1.OtherProperty1 = "New Other Property1 value";
Taco1.OtherProperty2 = "New Other Property2 value";
We will insert two records in AuditLog with the same TransactionID:
Having this approach
Any entity (table) could be traced
Reports will be readable
Only changes will be logged.