I have certain entities that have audit trail elements like LastUpdated and LastUpdatedBy. I am looking to determine the most appropriate way to effect an update of these fields to the current date and time and current user when a model is changed.
The simplest implementation would be to affect this change in my controller before I update the objectcontext but this would result in lots of repeated code. I could refactor this a bit and possibly create a helper method that I could call and pass the model too thus reducing things to a single line of code in my controller but I honestly would rather this be automatic, something the controller code didnt have to worry about.
Has anyone approached this problem before? What was your soluti开发者_StackOverflowon? What do you suggest?
(ps mvc and ef noob so there might be a framework type option I am missing)
I followed a similar pattern as @Nix, only I didn't use T4 since I prefer code-first development instead of the designer. If you have a Context
called MyDbContext
, you can partial class it to override the SaveChanges()
method. I also have an IAuditable
class that all my necessary entities extend from.
public interface IAuditable
{
User CreatedBy { get; set; }
DateTime? DateCreated { get; set; }
User ModifiedBy { get; set; }
DateTime? DateModified { get; set; }
User DeletedBy { get; set; }
DateTime? DateDeleted { get; set; }
}
// Classes that implement the IAuditable here.
public class User : EntityObject
{
public string Username { get; set; }
public string DisplayName { get; set; }
// etc...
}
partial class MyDbModel
{
public override int SaveChanges(SaveOptions options)
{
// Search all added, modified or deleted entities.
var entries = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted);
foreach (var entry in entries)
{
var auditable = entry.Entity as IAuditable;
if (auditable != null)
{
if (entry.State == EntityState.Added)
{
auditable.CreatedBy = null; // TODO - Get current user.
auditable.DateCreated = DateTime.Now;
auditable.ModifiedBy = null; // TODO - Same as CreatedBy?
auditable.DateModified = DateTime.Now;
}
else if (entry.State == EntityState.Modified)
{
auditable.ModifiedBy = null; // TODO - Get current user.
auditable.DateModified = DateTime.Now;
}
else if (entry.State == EntityState.Deleted)
{
auditable.DeletedBy = null; // TODO - Get current user.
auditable.DateDeleted = DateTime.Now;
}
}
}
return base.SaveChanges(options);
}
}
I have done stuff like this, i used T4 templates. See: Entity Framework Trigger Like Auditing
Basically I just made all entities extend an interface, and then in SaveChanges iterate through all that are "IAuditable" and set the update/insert dates.
Worked well for us, but we also went through and for every entity made sure the audit fields had the same names. Once you do that it is easy to generate the custom code automatically for those tables that contain the audit field. Thank make sense?
精彩评论