audit.net

How To Get Primary Key From AuditLog Table (Audit.Core.Configuration.AddCustomAction(ActionType.OnEventSaved)


I'm using this code block to save Audit information to a Detail table. During this save, I need to get the PK from the AuditLog table record that was just saved so I can add the Detail record.

Audit.Core.Configuration.AddCustomAction(ActionType.OnEventSaved, scope =>
{
   auditService.ConfigureAuditDetail(scope);
});

Since I only have scope available I am unable to locate the AuditLog entity except by a lookup against the context. Is this safe or could another record be saved before I get the right PK.

ctx.AuditLog.OrderByDescending(x => x.Id).FirstOrDefault().Id;

Is there any way to do this better?

    public void ConfigureAuditDetail(AuditScope scope)  
    {
        var efEvent = (scope.Event as AuditEventEntityFramework)?.EntityFrameworkEvent;
        
        List<EventEntryChange> currentChanges = new List<EventEntryChange>();
        var ctx = efEvent.GetDbContext() as DbContext;

       var auditLogId = ctx.AuditLog.OrderByDescending(x => x.Id).FirstOrDefault().Id;
     }

Solution

  • If you map your audit tables like this, so AuditLog have a collection of AuditLogDetails:

    public class AuditLog
    { 
        public int Id { get; set; }
        public ICollection<AuditLogDetail> Details { get; set; }
        public string Table { get; set; }
        public string Action { get; set; }
    }
    
    public class AuditLogDetail
    {
        public int Id { get; set; }
        public int AuditLogId { get; set; }
        public string Column { get; set; }
        public string Value { get; set; }
    }
    

    Then you can specify the mapping and the action for Audit EF like this:

    Audit.Core.Configuration.Setup()
        .UseEntityFramework(ef => ef
            .UseDbContext<MyContext>()
            .AuditTypeMapper(t => typeof(AuditLog))
            .AuditEntityAction<AuditLog>((auditEvent, entry, auditLog) =>
            {
                auditLog.Table = entry.Table;
                auditLog.Action = entry.Action;
                auditLog.Details = entry.ColumnValues.Select(c => new AuditLogDetail()
                {
                    Column = c.Key,
                    Value = c.Value.ToString()
                }).ToList();
            })
            .IgnoreMatchedProperties());
    

    So the audit entities are saved on the same transaction.