Extend base type and automatically update audit information on Entity

跟風遠走 提交于 2020-01-23 13:59:27

问题


I have an entity model that has audit information on every table (50+ tables)

 CreateDate
 CreateUser
 UpdateDate
 UpdateUser

Currently we are programatically updating audit information.

Ex:

  if(changed){
        entity.UpdatedOn = DateTime.Now;
        entity.UpdatedBy = Environment.UserName;
        context.SaveChanges();
   }

But I am looking for a more automated solution. During save changes, if an entity is created/updated I would like to automatically update these fields before sending them to the database for storage.

Any suggestion on how i could do this? I would prefer to not do any reflection, so using a text template is not out of the question.

A solution has been proposed to override SaveChanges and do it there, but in order to achieve this i would either have to use reflection (in which I don't want to do ) or derive a base class. Assuming i go down this route how would I achieve this?

For example

EXAMPLE_DB_TABLE
 CODE
 NAME
 --Audit Tables
 CREATE_DATE
 CREATE_USER
 UPDATE_DATE
 UPDATE_USER

And if i create a base class

 public abstract class IUpdatable{

     public virtual DateTime CreateDate {set;}
     public virtual string CreateUser { set;}
     public virtual DateTime UpdateDate { set;}
     public virtual string UpdateUser { set;}
 }

The end goal is to be able to do something like...

   public overrride void SaveChanges(){
        //Go through state manager and update audit infromation
        //FOREACH changed entity in state manager
        if(entity is IUpdatable){
           //If state is created... update create audit.
           //if state is updated... update update audit
        }
   }

But I am not sure how I go about generating the code that would extend the interface.


回答1:


Here was the final solution.

I basically check my model for the presence of 4 properties. If the entity contains

InsertedOn and InsertedBy and UpdatedOn and UpdatedBy I generate (using a tt file) the following entity that implements an IAuditable interface.

public interface IAuditable
{
    void SetInsertedOn(DateTime date);
    void SetInsertedBy(string user);
    void SetUpdatedOn(DateTime date);
    void SetUpdatedBy(string user);
}

public partial class ExampleDBtable: EntityObject, Audit.IAuditable
{
     //Normal EDMX stuff here..
     public static ExampleDBtable CreateExampleDBtable(int id, string code, string name, DateTime insertedOn, string insertedBy, DateTime updatedOn, string updatedBy)
       {

       }
       //Extension points.
    #region IAuditable Members

    public void SetInsertedOn(DateTime date)
    {
        this._InsertedOn = date;
    }

    public void SetInsertedBy(string user)
    {
        this._InsertedBy = user;
    }

    public void SetUpdatedOn(DateTime date)
    {
        this._UpdatedOn = date;
    }

    public void SetUpdatedBy(string user)
    {
        this._UpdatedBy = user;
    }

    #endregion

    }

I also generate code to handle the updating of audit information

   public ExampleDBObjectContext(string connectionString) : base(connectionString, "publicExampleDBObjectContext")
    {
        this.SavingChanges += new EventHandler(UpdateAuditInformation);
        this.OnContextCreated();
     }

And then finally I implemented the UpdateAuditInformation

   foreach (ObjectStateEntry entry in
            context.ObjectStateManager.GetObjectStateEntries(
            EntityState.Added | EntityState.Modified))
        {
              //Start pseudo code..
              if(entry.Entity is IAuditable){
                 IAuditable temp = entry.Entity as IAuditable;
                 temp.SetInsertedOn(DateTime.Now);
                 temp.SetInsertedBy(Env.GetUser());
                 ...

              }
        }

I opted not to show the .tt file because it looks horrible in the editor.




回答2:


Yes, I think you can do something like this. The general idea would be

  1. Handle ObjectContext.SavingChanges.
  2. In that event, call ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)
  3. Iterate the results and set properties if needed.



回答3:


Look to PostSharp. Very nice solution for such tasks.




回答4:


Is it not simpler to 'stamp' the updated rows via database triggers? Are the information provided in the database not adequate enough? (database user vs. os user)



来源:https://stackoverflow.com/questions/2588544/extend-base-type-and-automatically-update-audit-information-on-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!