Audit Trail com Entity Framework Core

Uma Trilha de Auditoria (também chamada de Log de Auditoria) é uma das maneiras mais eficazes de rastrear as ações dos usuários, fornecendo evidências de uma sequência de atividades que afetam informações, processos etc.

Usando o Entity Framework Core, podemos facilmente auditar as alterações, sobrescrevendo o método SaveChanges ().

Vamos ao que interessa

Defina a classe context e as classes de entidade que conformam seu modelo:

public class BloggingContext : DbContext
{
protected override void OnConfiguring
(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
"Server=localhost;Database=Blogging;User Id=sa;
Password=<YourStrong!Passw0rd>");
}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
view raw Models.cs hosted with ❤ by GitHub

Agora, devemos definir uma classe context auditável e o modelo AuditTrail:

public class BloggingAuditableContext : BloggingContext
{
public override int SaveChanges()
{
ChangeTracker.Entries().Where(p => p.State == EntityState.Modified).ToList().ForEach(entry =>
{
Audit(entry);
});
return base.SaveChanges();
}
private void Audit(EntityEntry entry)
{
foreach (var property in entry.Properties)
{
if (!property.IsModified)
continue;
var auditEntry = new AuditTrail
{
Table = entry.Entity.GetType().Name,
Column = property.Metadata.Name,
OldValue = property.OriginalValue.ToString(),
NewValue = property.CurrentValue.ToString(),
Date = DateTime.Now
};
this.AuditTrail.Add(auditEntry);
}
}
}
public class BloggingContext : DbContext
{
...
public DbSet<AuditTrail> AuditTrail { get; set; }
}
...
public class AuditTrail
{
public long AuditTrailId { get; set; }
public string Table { get; set; }
public string Column { get; set; }
public string OldValue { get; set; }
public string NewValue { get; set; }
public DateTime Date { get; set; }
}
view raw Models.cs hosted with ❤ by GitHub

Com os comandos de migração EF, criamos nossa base de dados e suas tabelas:

dotnet ef migrations add InitialCreate --context BloggingContext
dotnet ef database update --context BloggingContext

Vamos aos testes

Adicionaremos dados a nossa tabela Blog:

INSERT INTO [Blogging].[dbo].[Blogs] (Url) 
VALUES ('blog.victorleonardo.com');

Agora, devemos efetuar uma atualização ao registro que acabamos de inserir, utilizando nossa classe context auditável:

...
using (var auditableContext = new BloggingAuditableContext())
{
var blog = auditableContext.Blogs.FirstOrDefault();
blog.Url = "test.victorleonardo.com";
auditableContext.SaveChanges();
}
...

Voilà:

This image has an empty alt attribute; its file name is Screen-Shot-2019-04-28-at-4.41.21-PM.png