问题描述:

I have tried many different ways and looked at different posts, but still haven't come across a solution for this way of auditing. Below is my DBContext template file. I customised it by adding the OnContextCreated() partial method and assign the SavingChanges event to my OnSavingChanges event handler.

namespace ARSystem.Models

{

public partial class ARSEntities : ObjectContext

{

public ARSEntities()

: base("name=ARSEntities")

{

}

protected override void OnModelCreating(DbModelBuilder modelBuilder)

{

throw new UnintentionalCodeFirstException();

}

public string UserName { get; set; }

List<DBAudit> auditTrailList = new List<DBAudit>();

public enum AuditActions

{

I,

U,

D

}

partial void OnContextCreated()

{

this.SavingChanges += new EventHandler(OnSavingChanges);

}

public void OnSavingChanges(object sender, EventArgs e)

{

IEnumerable<ObjectStateEntry> changes = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified);

foreach (ObjectStateEntry stateEntryEntity in changes)

{

if (!stateEntryEntity.IsRelationship &&

stateEntryEntity.Entity != null &&

!(stateEntryEntity.Entity is DBAudit))

{//is a normal entry, not a relationship

DBAudit audit = this.AuditTrailFactory(stateEntryEntity, UserName);

auditTrailList.Add(audit);

}

}

if (auditTrailList.Count > 0)

{

foreach (var audit in auditTrailList)

{//add all audits

this.AddToDBAudit(audit);

}

}

}

private DBAudit AuditTrailFactory(ObjectStateEntry entry, string UserName)

{

DBAudit audit = new DBAudit();

audit.AuditId = Guid.NewGuid().ToString();

audit.RevisionStamp = DateTime.Now;

audit.TableName = entry.EntitySet.Name;

audit.UserName = UserName;

if (entry.State == EntityState.Added)

{//entry is Added

audit.NewData = GetEntryValueInString(entry, false);

audit.Actions = AuditActions.I.ToString();

}

else if (entry.State == EntityState.Deleted)

{//entry in deleted

audit.OldData = GetEntryValueInString(entry, true);

audit.Actions = AuditActions.D.ToString();

}

else

{//entry is modified

audit.OldData = GetEntryValueInString(entry, true);

audit.NewData = GetEntryValueInString(entry, false);

audit.Actions = AuditActions.U.ToString();

IEnumerable<string> modifiedProperties = entry.GetModifiedProperties();

//assing collection of mismatched Columns name as serialized string

audit.ChangedColumns = XMLSerializationHelper.XmlSerialize(modifiedProperties.ToArray());

}

return audit;

}

private string GetEntryValueInString(ObjectStateEntry entry, bool isOrginal)

{

if (entry.Entity is EntityObject)

{

object target = CloneEntity((EntityObject)entry.Entity);

foreach (string propName in entry.GetModifiedProperties())

{

object setterValue = null;

if (isOrginal)

{

//Get orginal value

setterValue = entry.OriginalValues[propName];

}

else

{

//Get orginal value

setterValue = entry.CurrentValues[propName];

}

//Find property to update

PropertyInfo propInfo = target.GetType().GetProperty(propName);

//update property with orgibal value

if (setterValue == DBNull.Value)

{//

setterValue = null;

}

propInfo.SetValue(target, setterValue, null);

}//end foreach

XmlSerializer formatter = new XmlSerializer(target.GetType());

XDocument document = new XDocument();

using (XmlWriter xmlWriter = document.CreateWriter())

{

formatter.Serialize(xmlWriter, target);

}

return document.Root.ToString();

}

return null;

}

public EntityObject CloneEntity(EntityObject obj)

{

DataContractSerializer dcSer = new DataContractSerializer(obj.GetType());

MemoryStream memoryStream = new MemoryStream();

dcSer.WriteObject(memoryStream, obj);

memoryStream.Position = 0;

EntityObject newObject = (EntityObject)dcSer.ReadObject(memoryStream);

return newObject;

}

public DbSet<Student> Students { get; set; }

public DbSet<User> Users { get; set; }

public DbSet<aspnet_Applications> aspnet_Applications { get; set; }

public DbSet<aspnet_Membership> aspnet_Membership { get; set; }

public DbSet<aspnet_Roles> aspnet_Roles { get; set; }

public DbSet<aspnet_SchemaVersions> aspnet_SchemaVersions { get; set; }

public DbSet<aspnet_Users> aspnet_Users { get; set; }

public DbSet<vw_aspnet_Applications> vw_aspnet_Applications { get; set; }

public DbSet<vw_aspnet_MembershipUsers> vw_aspnet_MembershipUsers { get; set; }

public DbSet<vw_aspnet_Roles> vw_aspnet_Roles { get; set; }

public DbSet<vw_aspnet_Users> vw_aspnet_Users { get; set; }

public DbSet<vw_aspnet_UsersInRoles> vw_aspnet_UsersInRoles { get; set; }

public DbSet<Cours> Courses { get; set; }

public DbSet<Enrollment> Enrollments { get; set; }

public DbSet<Modules> Modules { get; set; }

public DbSet<EnrollmentsByCourse> EnrollmentsByCourse { get; set; }

public DbSet<EnrollmentsByCourseAudit> EnrollmentsByCourseAudit { get; set; }

public DbSet<DBAudit> DBAudit { get; set; }

}

}

However, when I compile, i get the error message that:

Error 1 'ARSystem.Models.ARSEntities.OnModelCreating(System.Data.Entity.DbModelBuilder)': no suitable method found to override C:\Users\mngum\Documents\Visual Studio 2010\Projects\ARSystem\ARSystem\Models\ARSystem.Context.cs 35 33 ARSystem

I cannot see the OnContextCreated method in the DBContext metadata class but i can find it in the edmx designer. Please let me know how i can implement the OnContextCreated() method such that I can override the SavingChanges event for auditing purposes.

网友答案:

DbContext does not have an OnContextCreated event but that's not a problem because you don't need it to achieve the same. Instead with DbContext the SaveChanges method is overridable. So instead of your OnSavingChanges event handler you use:

public override int SaveChanges()
{
    // custom code...

    return base.SaveChanges();
}

This method will be called whenever you call ARSEntities.SaveChanges() and you can perform custom actions before you call the base.SaveChanges() of the base DbContext (ARSEntities must be derived from DbContext of course.)

You also can access the underlying ObjectContext from the DbContext:

public override int SaveChanges()
{
    var objectContext = ((IObjectContextAdapter)this).ObjectContext;

    // use methods and properties of ObjectContext now like
    // objectContext.ObjectStateManager, etc.

    // custom code...

    return base.SaveChanges();
}

Here was a similar question and answer about change auditing with EF 4.1/DbContext:

Entity Framework 4.1 DbContext Override SaveChanges to Audit Property Change

相关阅读:
Top