- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
LLBLGen Auditing framework
Joined: 20-Mar-2004
Hi All,
I'm in a process to design auditing mechanism for a WinForms application.
I would like to understand the difference (and advantages/disadvantage) between the class DatabaseAuditor and DatabaseAuditorSpecific provided in LLBLGen Auditing example. As both class has same base class AuditorBase.
SD.LLBLGen.Pro.Examples.Auditing.Auditors.DatabaseAuditor [DependencyInjectionInfo(typeof(CustomerEntity), "AuditorToUse")] [Serializable] public class DatabaseAuditor : AuditorBase
SD.LLBLGen.Pro.Examples.Auditing.Auditors.DatabaseAuditorSpecific [DependencyInjectionInfo(typeof(OrderEntity), "AuditorToUse")] [Serializable] public class DatabaseAuditorSpecific : AuditorBase
In Northwind example why do we need a table OrderAuditInfo that link between Orders and AuditInfo? Why can't we just store OrderAuditInfo.OrderID information into AuditInfo table? Because for each table we need to audit we have another AUDIT table for it.
Is LLBLGen Pro auto generate the DatabaseAuditor and DatabaseAuditorSpecific class?
Thanks in advance.
Regards Kaksss
Hi Kaksss,
kaksss wrote:
SD.LLBLGen.Pro.Examples.Auditing.Auditors.DatabaseAuditor [DependencyInjectionInfo(typeof(CustomerEntity), "AuditorToUse")] [Serializable] public class DatabaseAuditor : AuditorBase
SD.LLBLGen.Pro.Examples.Auditing.Auditors.DatabaseAuditorSpecific [DependencyInjectionInfo(typeof(OrderEntity), "AuditorToUse")] [Serializable] public class DatabaseAuditorSpecific : AuditorBase
Basically, the difference is that _DatabaseAuditor _store an independent log of some actions. And _DatabaseAuditorSpecific _store a log related to the relevant entities (in this case _OrderEntity _mapped from Order table).
kaksss wrote:
In Northwind example why do we need a table OrderAuditInfo that link between Orders and AuditInfo? Why can't we just store OrderAuditInfo.OrderID information into AuditInfo table? Because for each table we need to audit we have another AUDIT table for it.
Some programmers I know use this scenario, so they are able to:
- Keep integrity between relevant tables and their audit info.
- Query some historical log based on some predicates, like "ALL AuditInfo of ORDERS purchased by a certain CUSTOMER"
- Fetch a specific _OrdenEntity _and prefetch its related _OrderAuditInfo _collection.
This would be useful if you want at anytime, query the log information, and you have a multi-PK table. For example _OrderDetails _(PK = OrderId, ProductId), How would you store that info at _AuditInfo _and still make possible query some results based on a given _OrderId _and ProductId?
One pitfall is that the referential integrity forces to delete _OrderAuditInfo _records when you delete an Order. Note that you can keep the related _AuditInfo _information (_OrderAuditInfo _inherits from AuditInfo).
It is just another way people could perform audit mechanism. The example's intention is to demonstrate that you have flexibility to audit in your preferred/needed way. Its implementation should depends on project's scope/needs. In general this is not used for all Entities, just those that are relevant. In the example, we use _DatabaseAuditorSpecific _for some entities, and _DatabaseAuditor _for others.
kaksss wrote:
Is LLBLGen Pro auto generate the DatabaseAuditor and DatabaseAuditorSpecific class?
No. The examples uses some common practices. LLBLGen provides you the platform and facilities, but you should write your own audit code (to a txt file, to a xls file, to a DB table, to multiple DB tables, to a console, to a FAX machine, etc.).
If you have further questions, please let us know.
Joined: 20-Mar-2004
Hi daelmo,
Thanks for your reply.
From the Auditing example I have setup my app.config.
It is a WinForm client using MVP pattern so in my UI C# project I have a app.config as below.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<!-- ENABLING DEPENDENCY INJECTION
For more info read "LLBLGenPro Help - Depedency Injection mechanism" -->
<section name="dependencyInjectionInformation" type="SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionSectionHandler, SD.LLBLGen.Pro.ORMSupportClasses.NET20, Version=2.5.0.0, Culture=neutral, PublicKeyToken=ca73b74ba4e3ff27"/>
</configSections>
<!-- SPECIFYING DI INFORMATION
Comment/Uncomment assemblies to enabled/disabled Auditors injected to your EntityClasses
For more info read "LLBLGenPro Help - Depedency Injection mechanism" -->
<dependencyInjectionInformation>
<additionalAssemblies>
<assembly filename="XXX.layers.auditors.dll"/>
<assembly fullName="XXX.layers.auditors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</additionalAssemblies>
</dependencyInjectionInformation>
<appSettings>
<add key="SQLServerConnectionString" value="Data Source=DEVSERVER;Initial Catalog=TESTDB;Integrated Security=True"/>
<add key="autoDependencyInjectionDiscovery" value="true"/>
</appSettings>
<!-- Trace switches. Comment the switches out to avoid performance hits.
<system.diagnostics>
<switches>
<add name="SqlServerDQE" value="0" />
<add name="ORMGeneral" value="0" />
<add name="ORMStateManagement" value="0" />
<add name="ORMPersistenceExecution" value="0" />
</switches>
</system.diagnostics>
-->
</configuration>
but when I run the WinForm client I get the below exception in my class at this function call PerformDependencyInjection();
System.TypeInitializationException was unhandled
Message="The type initializer for 'SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionInfoProviderSingleton' threw an exception."
Source="SD.LLBLGen.Pro.ORMSupportClasses.NET20"
TypeName="SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionInfoProviderSingleton"
StackTrace:
at SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionInfoProviderSingleton.PerformDependencyInjection(Object injectionTarget)
at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.PerformDependencyInjection()
at XXX.layers.data.EntityClasses.PatientEntity.InitClassMembers() in C:\Projects\XXX.layers.data\EntityClasses\PatientEntity.cs:line 414
at XXX.layers.data.EntityClasses.PatientEntity.InitClassEmpty(IValidator validator, IEntityFields2 fields) in C:\Projects\XXX.layers.data\EntityClasses\PatientEntity.cs:line 459
at XXX.layers.data.EntityClasses.PatientEntity..ctor() in C:\Projects\XXX.layers.data\EntityClasses\PatientEntity.cs:line 76
at XXX.layers.dto.EntityClasses.PatientEntity..ctor() in C:\Projects\XXX.layers.dto\EntityClassesPartial\PatientEntity.cs:line 18
at XXX.layers.business.EntityClasses.PatientEntity..ctor() in C:\Projects\XXX.layers.business\EntityClasses\PatientEntity.cs:line 17
at XXX.layers.presenter.PatientViewPresenter..ctor(IPatientView view) in C:\Projects\XXX.layers.presenter\PatientViewPresenter.cs:line 17
at XXX.layers.win.UI.TestForm..ctor() in C:\Projects\XXX.layers.win.UI\TestForm.cs:line 21
at XXX.layers.win.UI.Program.Main() in C:\Projects\XXX.layers.win.UI\Program.cs:line 17
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Could you tell me what I need to do in order to make it work.
If I commented out below line in App.config and application is running and saving/fetching the data from SQL2005 but not doing any AUDIT thing...
<!--<assembly fullName="XXX.layers.auditors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>-->
Regards
Kaksss
Kaksss, Could you please post your Auditor class code (including the DI attribute information)?
For example:
[DependencyInjectionInfo(typeof(ProductEntity), "AuditorToUse",
ContextType = DependencyInjectionContextType.Singleton)]
[Serializable]
public class SimpleTextFileAuditor : AuditorBase
{
...
}
BTW, at your config flie:
<!-- SPECIFYING DI INFORMATION
Comment/Uncomment assemblies to enabled/disabled Auditors injected to your EntityClasses
For more info read "LLBLGenPro Help - Depedency Injection mechanism" -->
<dependencyInjectionInformation>
<additionalAssemblies>
<assembly filename="XXX.layers.auditors.dll"/>
<assembly fullName="XXX.layers.auditors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</additionalAssemblies>
</dependencyInjectionInformation>
<appSettings>
<add key="SQLServerConnectionString" value="Data Source=DEVSERVER;Initial Catalog=TESTDB;Integrated Security=True"/>
<add key="autoDependencyInjectionDiscovery" value="true"/>
</appSettings>
if you are specifying DI information at dependencyInjectionInformation, you don't need to set _autoDependencyInjectionDiscovery _to true, as this will turn on discovery over a lot of assemblies in your application's app-domain, automatic discovery of instance types in the assemblies used in your application.
Joined: 20-Mar-2004
NEXT TIME, please attach the code instead of posting it in a post, thanks -- Otis
Thanks, I will.
Hi daelmo,
namespace XXX.layers.auditors
{
/// <summary>
/// Auditor class intended to Audit entity information
/// to the database using LLBLGenPro Auditor Dependency Injection.
/// </summary>
/// <remarks>
/// This Auditor is injected to PatientEntity instances.
/// </remarks>
[DependencyInjectionInfo(typeof(PatientEntity), "AuditorToUse")]
[Serializable]
public class DatabaseAuditor : AuditorBase
{
#region Class Member Declarations
/// <summary>
/// Used to set the audit action type
/// </summary>
private enum AuditType
{
DeleteOfEntity=1,
DirectDeleteOfEntities,
DirectUpdateOfEntities,
DereferenceOfRelatedEntity,
ReferenceOfRelatedEntity,
EntityFieldGet,
EntityFieldSet,
InsertOfNewEntity,
UpdateOfExistingEntity,
LoadOfExistingEntity
}
// used to collect auditInfo entities
private List<AuditInfoEntity> _auditInfoEntities;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="DatabaseAuditor"/> class.
/// </summary>
public DatabaseAuditor()
{
_auditInfoEntities = new List<AuditInfoEntity>();
}
#endregion
#region Private methods
/// <summary>
/// Gets the current user ID from Session.
/// </summary>
/// <returns>Current logged-in user's ID</returns>
private string GetCurrentUserID()
{
return "amit";
//return SessionHelper.GetUserID();
}
/// <summary>
/// Constructs the audit info.
/// </summary>
/// <param name="affectedEntityName">Name of the affected entity.</param>
/// <param name="actionType">Type of the action.</param>
/// <param name="actionData">The action data.</param>
/// <returns></returns>
private AuditInfoEntity ConstructAuditInfo(string affectedEntityName, AuditType actionType, string actionData)
{
// create a new audit unit
AuditInfoEntity auditInfo = new AuditInfoEntity();
auditInfo.AffectedEntityName = affectedEntityName;
auditInfo.ActionDateTime = DateTime.Now;
auditInfo.AuditActionTypeId = (int)actionType;
auditInfo.UserId = GetCurrentUserID();
auditInfo.ActionData = actionData;
return auditInfo;
}
/// <summary>
/// Adds one audit entry to auditInfo entities.
/// </summary>
/// <param name="auditInfo">The audit info.</param>
private void AddAuditEntryToList(AuditInfoEntity auditInfo)
{
// adds for further DB persist
_auditInfoEntities.Add(auditInfo);
}
/// <summary>
/// Adds one audit entry to auditInfo entities.
/// </summary>
/// <param name="affectedEntityName">Name of the affected entity.</param>
/// <param name="actionType">Type of the action.</param>
/// <param name="actionData">The action data.</param>
private void AddAuditEntryToList(string affectedEntityName, AuditType actionType, string actionData)
{
// create a new audit unit
AuditInfoEntity auditInfo = ConstructAuditInfo(affectedEntityName, actionType, actionData);
// adds for further DB persist
AddAuditEntryToList(auditInfo);
}
/// <summary>
/// Direct persists the audit info. This method is used by methods that don't belong to a transaction
/// like AuditLoadOfEntity, AuditDirectDeleteOfEntities and AuditDirectUpdateOfEntites
/// </summary>
/// <param name="auditInfo">The audit info.</param>
private void DirectPersistAuditInfo(AuditInfoEntity auditInfo)
{
using (DataAccessAdapter adapter = new DataAccessAdapter())
{
adapter.SaveEntity(auditInfo);
}
}
/// <summary>
/// Gets the primary key info from entity.
/// </summary>
/// <param name="entity">A valid instance of IEntity2 object.</param>
/// <returns>Formatted string contained PK fields of the given entity</returns>
private string GetPrimaryKeyInfoFromEntity(IEntityCore entity)
{
// gets primary key fields
List<IEntityField2> pkFields = ((IEntity2)entity).PrimaryKeyFields;
// collect PK fields if the entity isn't new
string strPKEntityInfo = string.Empty;
if (!entity.IsNew)
{
// construct formatted string with pk fields
strPKEntityInfo = "PK(";
foreach (IEntityField2 pkField in pkFields)
{
strPKEntityInfo += string.Format("{0}:{1}, ", pkField.Name, pkField.CurrentValue.ToString());
}
// delete the extra ", " and ends with ")"
strPKEntityInfo = strPKEntityInfo.Remove(strPKEntityInfo.Length - 2, 2);
strPKEntityInfo += ")";
}
// returns PK info
return strPKEntityInfo;
}
#endregion
#region Public Audit methods
/// <summary>
/// Audits the successful delete of an entity from the database
/// </summary>
/// <param name="entity">The entity which was deleted.</param>
/// <remarks>As the entity passed in was deleted succesfully, reading values from the
/// passed in entity is only possible in this routine. After this call, the
/// state of the entity will be reset to Deleted again and reading the fields
/// will result in an exception. It's also recommended not to reference
/// the passed in entity in any audit entity you might want to persist as the entity doesn't
/// exist anymore in the database.</remarks>
public override void AuditDeleteOfEntity(IEntityCore entity)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(entity is AuditInfoEntity)
{
return;
}
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.DeleteOfEntity,
GetPrimaryKeyInfoFromEntity(entity));
}
/// <summary>
/// Audits the successful load of an entity from the database
/// </summary>
/// <param name="entity">The entity which was loaded.</param>
public override void AuditLoadOfEntity(IEntityCore entity)
{
/// Direct persist audit info to DB, because if the LoadOfEntity doesn't belong to a
/// outside persist operation, the auditInfo wont be saved.
/// Be aware that if an EntityCollection is fetched. This method will create a AuditInfoEntity
/// for each one of LoadEntity. Recommended to filter this operation as you project nature requieres.
///
/// This routine is documented for auditInfo table readability. Uncomment below code to test it.
/*
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if (entity is AuditInfoEntity)
{
return;
}
// construct audit info entity
AuditInfoEntity auditInfo = ConstructAuditInfo(
entity.LLBLGenProEntityName,
AuditType.LoadOfExistingEntity,
GetPrimaryKeyInfoFromEntity(entity));
// persist to DB
DirectPersistAuditInfo(auditInfo);
*/
}
/// <summary>
/// Audits the successful direct delete of entities in the database
/// </summary>
/// <param name="typeOfEntity">The type of entity of which entities were deleted.</param>
/// <param name="filter">The filter to filter out the entities to delete. Can be null and can
/// be an IPredicateExpression.</param>
/// <param name="relations">The relations to use with the filter. Can be null.</param>
/// <param name="numberOfEntitiesDeleted">The number of entities deleted.</param>
public override void AuditDirectDeleteOfEntities(Type typeOfEntity, IPredicate filter,
IRelationCollection relations, int numberOfEntitiesDeleted)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(typeOfEntity == typeof(AuditInfoEntity))
{
return;
}
// get filter's queryText
int tmpParameterCount = 0;
string strFilter = filter.ToQueryText(ref tmpParameterCount);
// construct parameters info
string strParameters = string.Empty;
foreach (IDataParameter param in filter.Parameters)
{
strParameters += (param.ParameterName + "=" + param.Value.ToString() + ". ");
}
// construct audit info entity
AuditInfoEntity auditInfo = ConstructAuditInfo(
typeOfEntity.FullName,
AuditType.DirectDeleteOfEntities,
string.Format("deleteFilter: {0}. filterParameters: {1}", strFilter, strParameters));
// add to auditinfo-to-save list
AddAuditEntryToList(auditInfo);
}
/// <summary>
/// Audits the successful dereference of related entity from the entity passed in.
/// </summary>
/// <param name="entity">The entity of which the related entity was dereferenced from.</param>
/// <param name="relatedEntity">The related entity which was dereferenced from entity</param>
/// <param name="mappedFieldName">Name of the mapped field onto the relation from entity to related
/// entity for which the related entity was dereferenced.</param>
public override void AuditDereferenceOfRelatedEntity(IEntityCore entity, IEntityCore relatedEntity,
string mappedFieldName)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(entity is AuditInfoEntity)
{
return;
}
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.DereferenceOfRelatedEntity,
string.Format("{0}. RelatedEntityName: {1}. MappedFieldName: {2}",
GetPrimaryKeyInfoFromEntity(entity), relatedEntity.LLBLGenProEntityName, mappedFieldName));
}
/// <summary>
/// Audits the succesful direct update of entities in the database.
/// </summary>
/// <param name="entity">The entity with the changed values which is used to produce the update
/// query.</param>
/// <param name="filter">The filter to filter out the entities to update. Can be null and can be an
/// IPredicateExpression.</param>
/// <param name="relations">The relations to use with the filter. Can be null.</param>
/// <param name="numberOfEntitiesUpdated">The number of entities updated.</param>
public override void AuditDirectUpdateOfEntities(IEntityCore entity, IPredicate filter,
IRelationCollection relations, int numberOfEntitiesUpdated)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(entity is AuditInfoEntity)
{
return;
}
// get filter's queryText
int tmpParameterCount = 0;
string strFilter = filter.ToQueryText(ref tmpParameterCount);
// construct parameters info
string strParameters = string.Empty;
foreach (IDataParameter param in filter.Parameters)
{
strParameters += (param.ParameterName + "=" + param.Value.ToString() + ". ");
}
// construct update-new-values info of the direct update
string updatedFields = string.Empty;
foreach (IEntityField2 field in ((IEntity2)entity).Fields)
{
if (field.IsChanged)
{
updatedFields += (field.Name + "=" + field.CurrentValue.ToString() + ". ");
}
}
// construc audit info entity
AuditInfoEntity auditInfo = ConstructAuditInfo(
entity.LLBLGenProEntityName,
AuditType.DirectUpdateOfEntities,
string.Format("updatedFields: {0} updateFilter: {1}. filterParameters: {2}", updatedFields, strFilter, strParameters));
// add to auditinfo-to-save list
AddAuditEntryToList(auditInfo);
}
/// <summary>
/// Audits when an entity field is get succesfully.
/// </summary>
/// <param name="entity">The entity a field was get.</param>
/// <param name="fieldIndex">Index of the field which got.</param>
public override void AuditEntityFieldGet(IEntityCore entity, int fieldIndex)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(entity is AuditInfoEntity)
{
return;
}
/// NOTE: Uncomment this you want to track the got fields by an user.
/// This was commented to avoid hundreds of irrelevant audit info.
/*
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.EntityFieldGet,
string.Format("{0}. FieldGet: {1}",
GetPrimaryKeyInfoFromEntity(entity),
((IEntity2)entity).Fields[fieldIndex].Name));
* */
}
/// <summary>
/// Audits when an entity field is set succesfully to a new value.
/// </summary>
/// <param name="entity">The entity a field was set to a new value.</param>
/// <param name="fieldIndex">Index of the field which got a new value.</param>
/// <param name="originalValue">The original value of the field with the index passed in
/// before it received a new value.</param>
public override void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object originalValue)
{
// avoid to adit an AuditInfoEntity. This would create an Overflow efect.
if (entity is AuditInfoEntity)
{
return;
}
// used to store the change experimented by a field.
string originalValueAsString = string.Empty;
string currentValue = string.Empty;
// sets VALUE OR NULL for originalValue and uses it as string.
if (originalValue != null)
{
originalValueAsString = originalValue.ToString();
}
else
{
originalValueAsString = "NULL";
}
// sets VALUE OR NULL for currentValue and uses it as string.
if (entity.GetCurrentFieldValue(fieldIndex) != null)
{
currentValue = entity.GetCurrentFieldValue(fieldIndex).ToString();
}
else
{
currentValue = "NULL";
}
// post the field change info
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.EntityFieldSet,
string.Format("{0}. FieldSet: {1}. OriginalValue: {2}. CurrentValue: {3}",
GetPrimaryKeyInfoFromEntity(entity),
((IEntity2) entity).Fields[fieldIndex].Name,
originalValueAsString, currentValue));
}
/// <summary>
/// Audits the successful insert of a new entity into the database.
/// </summary>
/// <param name="entity">The entity saved successfully into the database.</param>
public override void AuditInsertOfNewEntity(IEntityCore entity)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(entity is AuditInfoEntity)
{
return;
}
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.InsertOfNewEntity,
GetPrimaryKeyInfoFromEntity(entity));
}
/// <summary>
/// Audits the successful reference of related entity from the entity passed in.
/// </summary>
/// <param name="entity">The entity of which the related entity was dereferenced from.</param>
/// <param name="relatedEntity">The related entity which was dereferenced from entity</param>
/// <param name="mappedFieldName">Name of the mapped field onto the relation from entity to related
/// entity for which the related entity was referenced.</param>
public override void AuditReferenceOfRelatedEntity(IEntityCore entity, IEntityCore relatedEntity, string mappedFieldName)
{
// avoid to audit into AuditInfoEntity (this would create an overflow effect). This is necessary if this auditor is injected into
// all entities, thus also in the AuditInfoEntity
if(entity is AuditInfoEntity)
{
return;
}
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.InsertOfNewEntity,
string.Format("{0}. RelatedEntityName: {0}. MappedFieldName: {1}",
GetPrimaryKeyInfoFromEntity(entity), relatedEntity.LLBLGenProEntityName, mappedFieldName));
}
/// <summary>
/// Audits the successful update of an existing entity in the database
/// </summary>
/// <param name="entity">The entity updated successfully in the database.</param>
public override void AuditUpdateOfExistingEntity(IEntityCore entity)
{
// avoid to adit an AuditInfoEntity. This would create an Overflow efect.
if (entity is AuditInfoEntity)
{
return;
}
AddAuditEntryToList(
entity.LLBLGenProEntityName,
AuditType.UpdateOfExistingEntity,
GetPrimaryKeyInfoFromEntity(entity));
}
/// <summary>
/// Gets the audit entities to save. Audit entities contain the audit information stored inside this auditor.
/// </summary>
/// <returns>The list of audit entities to save, or null if there are no audit entities to save</returns>
/// <remarks>Do not remove the audit entities and audit information from this auditor when this method is
/// called, as the transaction in which the save takes place can fail and retried which will result in another call
/// to this method</remarks>
public override System.Collections.IList GetAuditEntitiesToSave()
{
return _auditInfoEntities;
}
/// <summary>
/// The transaction with which the audit entities requested from GetAuditEntitiesToSave were saved.
/// Use this method to clear any audit data in this auditor as all audit information is persisted successfully.
/// </summary>
public override void TransactionCommitted()
{
_auditInfoEntities.Clear();
}
#endregion
}
}