-
-
Save betillogalvanfbc/c394d31803e997603214d2b87394343d to your computer and use it in GitHub Desktop.
Auditable Models for Entity Framework in DotNet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace EF.Core.Audit | |
{ | |
public abstract class Auditable | |
{ | |
public virtual DateTime CreatedAt { get; set; } | |
public virtual DateTime? UpdatedAt { get; set; } | |
public virtual DateTime? DeletedAt { get; set; } | |
} | |
public abstract class Auditable<TId>: Auditable | |
{ | |
public virtual TId CreatedBy { get; set; } | |
public virtual TId UpdatedBy { get; set; } | |
public virtual TId DeletedBy { get; set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using Microsoft.EntityFrameworkCore; | |
namespace EF.Core.Audit | |
{ | |
public static class AuditableExtensions | |
{ | |
public static void FilterSoftDeletedEntries<TModel>(this ModelBuilder builder) where TModel: Auditable | |
{ | |
builder.Entity<TModel>() | |
.HasQueryFilter(p => p.DeletedAt == null); | |
} | |
public static void EnsureAudit<TId>(this DbContext context, TId id = default(TId)) | |
{ | |
context.ChangeTracker.DetectChanges(); | |
var markedAsCreated = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Added); | |
foreach (var item in markedAsCreated) | |
{ | |
if (item.Entity is Auditable<TId> entity) | |
{ | |
// Only update the UpdatedAt flag - only this will get sent to the Db | |
entity.CreatedAt = DateTime.UtcNow; | |
entity.CreatedBy = id; | |
} | |
else if (item.Entity is Auditable entity1) | |
{ | |
entity1.CreatedAt = DateTime.UtcNow; | |
} | |
} | |
var markedAsUpdated = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified); | |
foreach (var item in markedAsUpdated) | |
{ | |
if (item.Entity is Auditable<TId> entity) | |
{ | |
// Only update the UpdatedAt flag - only this will get sent to the Db | |
entity.UpdatedAt = DateTime.UtcNow; | |
entity.UpdatedBy = id; | |
} | |
else if (item.Entity is Auditable entity1) | |
{ | |
entity1.UpdatedAt = DateTime.UtcNow; | |
} | |
} | |
var markedAsDeleted = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Deleted); | |
foreach (var item in markedAsDeleted) | |
{ | |
if (item.Entity is Auditable<TId> entity) | |
{ | |
// Set the entity to unchanged (if we mark the whole entity as Modified, every field gets sent to Db as an update) | |
item.State = EntityState.Unchanged; | |
// Only update the DeletedAt flag - only this will get sent to the Db | |
entity.DeletedAt = DateTime.UtcNow; | |
entity.DeletedBy = id; | |
} | |
else if (item.Entity is Auditable entity1) | |
{ | |
item.State = EntityState.Unchanged; | |
entity1.DeletedAt = DateTime.UtcNow; | |
} | |
} | |
} | |
public static void EnsureAudit(this DbContext context) | |
{ | |
context.ChangeTracker.DetectChanges(); | |
var markedAsCreated = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Added); | |
foreach (var item in markedAsCreated) | |
{ | |
if (item.Entity is Auditable entity) | |
{ | |
// Only update the UpdatedAt flag - only this will get sent to the Db | |
entity.CreatedAt = DateTime.UtcNow; | |
} | |
} | |
var markedAsUpdated = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified); | |
foreach (var item in markedAsUpdated) | |
{ | |
if (item.Entity is Auditable entity) | |
{ | |
// Only update the UpdatedAt flag - only this will get sent to the Db | |
entity.UpdatedAt = DateTime.UtcNow; | |
} | |
} | |
var markedAsDeleted = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Deleted); | |
foreach (var item in markedAsDeleted) | |
{ | |
if (item.Entity is Auditable entity) | |
{ | |
// Set the entity to unchanged (if we mark the whole entity as Modified, every field gets sent to Db as an update) | |
item.State = EntityState.Unchanged; | |
// Only update the DeletedAt flag - only this will get sent to the Db | |
entity.DeletedAt = DateTime.UtcNow; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment