|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionAudit logging is an important issue while building enterprise systems. The simplest form of audit logging is recording who created/updated an object or a record in the database respectively and when it was done. We perform four basic operations on a domain object. These are:
Data access layer is a good place to perform automated audit logging whenever one of the operations above is executed. In this article we will try to perform simple logging that meets the following minimal requirements:
Class ModelWe have three interfaces directly related to audit logging and
public abstract class InsertLoggableDomainObject
If we want our domain objects to be audit logged by our NHibernate SetupInheriting our domain objects from one of the base loggable classes does not provide us NHibernate MappingsAs any other <?xml version='1.0' encoding='utf-8'?>
<hibernate-mapping
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns='urn:nhibernate-mapping-2.0'>
<class
name='Fully Qualified Class name comes here'
table='Table name'>
<id name='Identity field name'
column='Identity column to which identity field maps'
unsaved-value='0'>
<generator class='identity'/>
</id>
<!--Managed versioning support. Defined in IVersionedEntity interface -->
<version name='_version' column='Version' access='field'
unsaved-value='0' type='Int64'/>
<!--Log field mappings -->
<property name='SysCreatedOn' column='SysCreatedOn'
type='NHibernate.Nullables2.NullableDateTimeType,
NHibernate.Nullables2'/>
<property name='SysCreatedBy' column='SysCreatedBy'
type='NHibernate.Nullables2.NullableInt32Type,
NHibernate.Nullables2'/>
<property name='SysLastUpdatedOn' column='SysLastUpdatedOn'
type='NHibernate.Nullables2.NullableDateTimeType,
NHibernate.Nullables2'/>
<property name='SysLastUpdatedBy' column='SysLastUpdatedBy'
type='NHibernate.Nullables2.NullableInt32Type,
NHibernate.Nullables2'/>
<!-- Some other field, relation, subclass and other kind of mappings
from this point on-->
</class>
</hibernate-mapping>
We use NHibernate Session InitializationThis step is simple. Either you directly manage IInterceptor ImplementationYou can think of an interceptor as a hook utility to the data access layer. public class MyAuditLogger:IInterceptor
{
#region IInterceptor Members
public int[] FindDirty(object entity, object id,
object[] currentState, object[] previousState,
string[] propertyNames,
global::NHibernate.Type.IType[] types)
{
return null;
}
public object Instantiate(Type type, object id)
{
return null;
}
public object IsUnsaved(object entity)
{
return null;
}
public void OnDelete(object entity, object id, object[] state,
string[] propertyNames, global::NHibernate.Type.IType[] types)
{
}
public bool OnFlushDirty(object entity, object id, object[] currentState,
object[] previousState, string[] propertyNames,
global::NHibernate.Type.IType[] types)
{
if (entity is IUpdateLogable)
{
SetUpdateLoggableValues(currentState, propertyNames);
return true;
}
else if (entity is IModifyLogable)
{
SetModifyLoggableValues_OnUpdate(currentState, propertyNames);
return true;
}
else
{
return true;
}
}
public bool OnLoad(object entity, object id, object[] state,
string[] propertyNames, global::NHibernate.Type.IType[] types)
{
return true;
}
public bool OnSave(object entity, object id, object[] state,
string[] propertyNames, global::NHibernate.Type.IType[] types)
{
if (entity is IInsertLogable)
{
SetInsertLoggableValues(state, propertyNames);
return true;
}
else if (entity is IModifyLogable)
{
SetModifyLoggableValues_OnInsert(state, propertyNames);
return true;
}
else
{
return true;
}
}
public void PostFlush(System.Collections.ICollection entities)
{
}
public void PreFlush(System.Collections.ICollection entities)
{
}
private Hashtable GetInsertLoggablePropertyIndexes(string[] Properties)
{
Hashtable result = new Hashtable();
int propCounter = 0;
for (int i = 0; i < Properties.Length; i++)
{
if (Properties[i].ToLower() == "syscreatedby")
{
propCounter++;
result.Add("syscreatedby", i);
}
else if (Properties[i].ToLower() == "syscreatedon")
{
propCounter++;
result.Add("syscreatedon", i);
}
if (propCounter == 2)
{
break;
}
}
return result;
}
private Hashtable GetUpdateLoggablePropertyIndexes(string[] Properties)
{
Hashtable result = new Hashtable();
int propCounter = 0;
for (int i = 0; i < Properties.Length ; i++)
{
if (Properties[i].ToLower() == "syslastupdatedby")
{
propCounter++;
result.Add("syslastupdatedby", i);
}
else if (Properties[i].ToLower() == "syslastupdatedon")
{
propCounter++;
result.Add("syslastupdatedon", i);
}
if (propCounter == 2)
{
break;
}
}
return result;
}
private Hashtable GetModifyLoggablePropertyIndexes(string[] Properties)
{
Hashtable result = new Hashtable();
int propCounter = 0;
for (int i = 0; i < Properties.Length; i++)
{
if (Properties[i].ToLower() == "syscreatedby")
{
propCounter++;
result.Add("syscreatedby", i);
}
else if (Properties[i].ToLower() == "syscreatedon")
{
propCounter++;
result.Add("syscreatedon", i);
}
else if (Properties[i].ToLower() == "syslastupdatedby")
{
propCounter++;
result.Add("syslastupdatedby", i);
}
else if (Properties[i].ToLower() == "syslastupdatedon")
{
propCounter++;
result.Add("syslastupdatedon", i);
}
if (propCounter == 4)
{
break;
}
}
return result;
}
private void SetInsertLoggableValues(object[] state, string[] Properties)
{
Hashtable indexes = GetInsertLoggablePropertyIndexes(Properties);
if (indexes.Count != 2)
{
throw new Exception("Can't log IInsertLoggable entity.
Indexes not found!");
}
int index = -1;
if(indexes["syscreatedby"] == null)
{
throw new Exception("Can't log IInsertLoggable entity.
Index value for SysCreatedBy does not exist!");
}
index = (int)indexes["syscreatedby"];
state[index] = ContextManager.Instance.ActivePersonID;
if (indexes["syscreatedon"] == null)
{
throw new Exception("Can't log IInsertLoggable entity.
Index value for SysCreatedOn does not exist!");
}
index = (int)indexes["syscreatedon"];
state[index] = DateTime.Now;
}
private void SetUpdateLoggableValues(object[] state, string[] Properties)
{
Hashtable indexes = GetUpdateLoggablePropertyIndexes(Properties);
if (indexes.Count != 2)
{
throw new Exception("Can't log IUpdateLoggable entity.
Indexes not found!");
}
int index = -1;
if (indexes["syslastupdatedby"] == null)
{
throw new Exception("Can't log IUpdateLoggable entity.
Index value for SysLastUpdatedBy does not exist!");
}
index = (int)indexes["syslastupdatedby"];
state[index] = ContextManager.Instance.ActivePersonID;
if (indexes["syslastupdatedon"] == null)
{
throw new Exception("Can't log IUpdateLoggable entity.
Index value for SysLastUpdatedOn does not exist!");
}
index = (int)indexes["syslastupdatedon"];
state[index] = DateTime.Now;
}
private void SetModifyLoggableValues_OnInsert(object[] state,
string[] Properties)
{
Hashtable indexes = GetModifyLoggablePropertyIndexes(Properties);
if (indexes.Count != 4)
{
throw new Exception("Can't log IInsertLoggable entity.
Indexes not found!");
}
int index = -1;
if (indexes["syscreatedby"] == null)
{
throw new Exception("Can't log IInsertLoggable entity.
Index value for SysCreatedBy does not exist!");
}
index = (int)indexes["syscreatedby"];
state[index] = ContextManager.Instance.ActivePersonID;
if (indexes["syscreatedon"] == null)
{
throw new Exception("Can't log IInsertLoggable entity.
Index value for SysCreatedOn does not exist!");
}
index = (int)indexes["syscreatedon"];
state[index] = DateTime.Now;
}
private void SetModifyLoggableValues_OnUpdate(object[] state,
string[] Properties)
{
Hashtable indexes = GetModifyLoggablePropertyIndexes(Properties);
if (indexes.Count != 4)
{
throw new Exception("Can't log IModifyLogable entity.
Indexes not found!");
}
int index = -1;
if (indexes["syslastupdatedby"] == null)
{
throw new Exception("Can't log IModifyLogable entity.
Index value for SysLastUpdatedBy does not exist!");
}
index = (int)indexes["syslastupdatedby"];
state[index] = ContextManager.Instance.ActivePersonID;
if (indexes["syslastupdatedon"] == null)
{
throw new Exception("Can't log IModifyLogable entity.
Index value for SysLastUpdatedOn does not exist!");
}
index = (int)indexes["syslastupdatedon"];
state[index] = DateTime.Now;
}
#endregion
}
Actually we only implemented Property validation methodsThese methods simply loop through domain object properties, already supported by
Log data settersThese methods simply
Remarks and Future Work SuggestionsThe sample implementation was one of my first experiences with I've read about some difficulties and tips about performing interceptor operations and logging using the Further work can focus on logging to different databases by defining loggable domain object
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||