LLBLGen Auditing framework

Posts   
 
    
kakaiya
User
Posts: 182
Joined: 20-Mar-2004
# Posted on: 08-Nov-2007 04:22:52   

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

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 08-Nov-2007 06:21:54   

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.

David Elizondo | LLBLGen Support Team
kakaiya
User
Posts: 182
Joined: 20-Mar-2004
# Posted on: 08-Nov-2007 06:41:10   

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

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 08-Nov-2007 07:20:53   

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.

David Elizondo | LLBLGen Support Team
kakaiya
User
Posts: 182
Joined: 20-Mar-2004
# Posted on: 08-Nov-2007 08:55:13   

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
    }
}

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 08-Nov-2007 14:51:45   

Where is the location of XXX.layers.auditors.dll with respect to the soltuion folders?

kakaiya
User
Posts: 182
Joined: 20-Mar-2004
# Posted on: 08-Nov-2007 23:01:24   

Hi Walaa,

I have solved this issue as XXX.layers.auditors.dll file wa not in application bin folder.

Thank you,

Kaksss