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

Viewed 88

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;
     }
2 Answers

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.

If you have access to the actual entity you are saving via Entity Framework, you can extract the Id or Primary Key Value from it directly. I do it using an extension method I wrote:

public static object GetPrimaryKeyValue(this EntityEntry entry)
{
    return entry.Metadata
        .FindPrimaryKey().Properties
        .Select(property => entry.Property(property.Name).CurrentValue)
        .FirstOrDefault(value => value != null);
}
Related