Jasinski Technical Wiki

Navigation

Home Page
Index
All Pages

Quick Search
»
Advanced Search »

Contributor Links

Create a new Page
Administration
File Management
Login/Logout
Your Profile

Other Wiki Sections

Software

PoweredBy

Page History: AuditableBase Class for Automatically Tracking Data Changes - Entity Framework Code First

Compare Page Revisions



« Older Revision - Back to Page History - Newer Revision »


Page Revision: Fri, May 19, 2017, 12:09 PM


Reusable Code

AuditableBase Class

public abstract class AuditableBase
{
    [Required]
    public DateTimeOffset CreatedOn { get; set; }

    [Required]
    public DateTimeOffset UpdatedOn { get; set; }

    [Required]
    public int CreatedBy { get; set; }

    [Required]
    public int UpdatedBy { get; set; }

    /* TODO: Uncomment CreatedByUser and UpdatedByUser */
    //[ForeignKey("CreatedBy")]
    //public User CreatedByUser { get; set; }

    //[ForeignKey("UpdatedBy")]
    //public User UpdatedByUser { get; set; }

    public void Audit(int byUserId, bool createNew)
    {
        var dtNow = DateTime.UtcNow;

        if (createNew)
        {
            CreatedOn = dtNow;
            CreatedBy = byUserId;
        }

        UpdatedOn = dtNow;
        UpdatedBy = byUserId;
    }
}

Additional Methods on DataContext Class

Pre-Dot-Net-Core Version
#region Auditing

public int SaveChanges(int byUserId)
{
    Audit(byUserId);
    return base.SaveChanges();
}

public async Task<int> SaveChangesAsync(int byUserId)
{
    Audit(byUserId);
    return await base.SaveChangesAsync();
}

public void Audit(int byUserId)
{
    ChangeTracker.DetectChanges(); // normally called by base
    var context = ((IObjectContextAdapter)this).ObjectContext;
    var changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified);

    foreach (var entry in changes)
    {
        if (!(entry.Entity is AuditableBase))
            continue;

        var auditable = (AuditableBase)entry.Entity;
        var createNew = (entry.State == EntityState.Added);
        auditable.Audit(byUserId, createNew);
    }
}

#endregion

Dot Net Core Version
#region Auditing

public int SaveChanges(int byUserId)
{
    Audit(byUserId);
    return base.SaveChanges();
}

public async Task<int> SaveChangesAsync(int byUserId)
{
    Audit(byUserId);
    return await base.SaveChangesAsync();
}

public void Audit(int byUserId)
{
    var items = this.ChangeTracker.Entries()
        .Where(x => (x.State == EntityState.Added || x.State == EntityState.Modified)
                    && x.Entity != null
                    && x.Entity is AuditableBase)
        .Select(x => x)
        .ToList();

    foreach (var item in items)
    {
        var auditable = (AuditableBase)item.Entity;
        var createNew = (item.State == EntityState.Added);
        auditable.Audit(byUserId, createNew);
    }
}

#endregion

ScrewTurn Wiki version 3.0.1.400. Some of the icons created by FamFamFam. Except where noted, all contents Copyright © 1999-2024, Patrick Jasinski.