secret
Created

AuxDbContext

  • Download Gist
AuxDbContext.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/// <summary>
/// Delegate definition for when the database context has been successfully saved.
/// </summary>
public delegate void OnContextSaved();
 
/// <summary>
/// Database context extensions. Provides additional functionality.
/// </summary>
/// <remarks>
/// <list type="1">
/// <listheader>Additions</listheader>
/// <item>Extra <see cref="System.Data.Entity.Validation.DbEntityValidationException"/> message descriptions.</item>
/// <item>OnSaved event handler. Allows hooks into a successful save.</item>
/// <item>Audit history. Provides a storage model for audit tracking.</item>
/// </list>
/// </remarks>
public abstract class AuxDbContext : DbContext
{
/// <summary>
/// OnSaved Event - called after a successful SaveChanges()
/// </summary>
public event OnContextSaved OnSaved;
 
/// <summary>
/// Initialize a new instance of Aux.Data.AuxDbContext
/// </summary>
/// <param name="connection">The connection string.</param>
public AuxDbContext(string connection)
: base(connection)
{
// Add an additional OnSaving Event.
// This checks any modified entities to see if they have the
// [Audit] attribute on them for history tracking.
((IObjectContextAdapter)this).ObjectContext.SavingChanges += OnSaving;
}
 
/// <summary>
/// Saves all changes made in this context to the underlying database.
/// </summary>
/// <returns>The number of objects written to the underlying database.</returns>
public override int SaveChanges()
{
int result;
 
try
{
result = base.SaveChanges();
}
catch (DbEntityValidationException ex)
{
// Catch any validation issues and reformat their error.
// The default error gives nothing after the fact so attempt to give
// some more meaningful information in the exceptoin message.
 
var messages = ex.EntityValidationErrors
.Where(e => !e.IsValid)
.Select(errors => errors
.ValidationErrors.ToString(", ", e => " { " + errors.Entry.Entity.GetType().Name + "." + e.PropertyName + ": " + e.ErrorMessage + " } "));
 
throw new DbEntityValidationException("Validation failed for one or more entities: " + messages.ToString("\r\n"), ex);
}
 
if (OnSaved != null)
{
OnSaved();
}
 
return result;
}
 
/// <summary>
/// Check for audit tracking while saving a record
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void OnSaving(object sender, EventArgs args)
{
// Only look at entities that were marked as modified
foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == System.Data.EntityState.Modified))
{
var properties = entry.Entity.GetType().GetProperties();
 
// Check each entity property for things with the Audit attribute.
foreach (var property in properties)
{
var audit = property.GetCustomAttributes(typeof(AuditAttribute), true);
 
// Has a single audit property (multiple not allowed, nor does it make sense)
if (audit != null && audit.Length == 1)
{
var member = entry.Member(property.Name);
// Get the current value.
string current = (member.CurrentValue != null)
? member.CurrentValue.ToString()
: null;
 
string original = String.Empty;
 
// Simple property or complex type
if (member is DbPropertyEntry)
{
original = ((member as DbPropertyEntry).OriginalValue != null)
? (member as DbPropertyEntry).OriginalValue.ToString()
: null;
 
// Check if it really changed, sometimes
// (member as DbPropertyEntry).IsModified throws false positive.
if (original == current)
{
continue; // no change
}
}
else if (member is DbReferenceEntry)
{
// Original values not available for references
original = "{ Reference Type - Original not available. }";
}
 
var h = new History
{
Changed = DateTime.Now,
User = Thread.CurrentPrincipal.Identity.Name,
OriginalValue = original,
NewValue = current,
Column = member.Name,
Table = (this.IsProxy(entry.Entity)
? entry.Entity.GetType().BaseType
: entry.Entity.GetType())
.FullName,
EntityId = History.FormatEntityKey(this.GetEntityKey(entry.Entity).EntityKeyValues.ToDictionary(k => k.Key, v => v.Value))
};
 
// Ensure that we have something for the user name
if (String.IsNullOrWhiteSpace(h.User))
{
h.User = "{ Anonymous.User }";
}
 
Set<History>().Add(h);
}
}
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.