How to have audit logs in same transaction as changed entities when using DbContextHelper #755
Replies: 2 comments 4 replies
-
|
Can you provide more details about your configuration and your custom audit data provider? |
Beta Was this translation helpful? Give feedback.
-
|
The following example demonstrates how to implement a custom data provider that reuses the The The This pattern ensures that both the audited entity changes and their corresponding audit records are saved using the same transactional context. public class YourDbContext : DbContext
{
private readonly DbContextHelper _helper = new DbContextHelper();
private readonly IAuditDbContext _auditContext;
public DbSet<OrderEntity> Orders { get; set; }
public DbSet<AuditEventEntity> Audits { get; set; }
public YourDbContext()
{
_auditContext = new DefaultAuditContext(this);
_helper.SetConfig(_auditContext);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(...);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
return _helper.SaveChanges(_auditContext, () =>
{
// Begin a transaction before saving
this.Database.BeginTransaction();
return base.SaveChanges(acceptAllChangesOnSuccess);
});
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
return await _helper.SaveChangesAsync(_auditContext, async () =>
{
// Begin a transaction
await this.Database.BeginTransactionAsync(cancellationToken);
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}, cancellationToken);
}
// Custom save changes method that bypasses the audit process, call this method to save the Audit entities
public int SaveAuditChanges(bool acceptAllChangesOnSuccess = true)
{
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public Task<int> SaveAuditChangesAsync(bool acceptAllChangesOnSuccess = true, CancellationToken cancellationToken = default)
{
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
}
public class CustomDataProvider : AuditDataProvider
{
public override object InsertEvent(AuditEvent auditEvent)
{
// Get the DbContext from the EF AuditEvent
var dbContext = GetDbContext(auditEvent);
// Insert the audit event into the database
dbContext.Audits.Add(new AuditEventEntity
{
AuditData = auditEvent.ToJson()
//...
});
dbContext.SaveAuditChanges();
// Commit the transaction
dbContext.Database.CurrentTransaction?.Commit();
return null;
}
public override async Task<object> InsertEventAsync(AuditEvent auditEvent, CancellationToken cancellationToken = default)
{
// Get the DbContext from the EF AuditEvent
var dbContext = GetDbContext(auditEvent);
// Insert the audit event into the database
dbContext.Audits.Add(new AuditEventEntity
{
AuditData = auditEvent.ToJson()
//...
});
// Save the audit (we want to bypass)
await dbContext.SaveAuditChangesAsync(cancellationToken: cancellationToken);
// Commit the transaction
if (dbContext.Database.CurrentTransaction != null)
{
await dbContext.Database.CurrentTransaction.CommitAsync(cancellationToken: cancellationToken);
}
return null;
}
private static YourDbContext GetDbContext(AuditEvent auditEvent)
{
return auditEvent.GetEntityFrameworkEvent().GetDbContext() as YourDbContext;
}
}
public class OrderEntity
{
public int Id { get; set; }
public double Amount { get; set; }
}
[AuditIgnore]
public class AuditEventEntity
{
public int Id { get; set; }
public string AuditData { get; set; }
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I want the audit logs to be in the same transaction as the entity they are logging.
I know there is a note in the docs about overriding
OnsScopeCreated(), etc. However, that seems to assume you are inheriting from theAuditDbContext. I am not doing this. I'm just using theDbContextHelper.I have all of my entities logging, but the audit items come in later and end up in a different transaction.
How do I do this if I'm not inheriting from
AuditDbContext? I foundAudit.Core.Configuration.AddOnSavingActionandAudit.Core.Configuration.AddOnCreatedAction, which I think might be the way to do it, but the docs say to put my custom saving logic in there, and seem to say that I have to bypass my data provider, but I'm using a customAuditDataProvider, so I don't want to use a null provider.Is there any way to do this?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions