简体   繁体   中英

Entity Framework - generic auditing by entity or table

I need to audit data in some tables in my server database so my clients can take partial updates (by table/entity). Data in the server database is only edited from the server website.

The audits will be requested by a client: WHERE Id > [Clients Last Id] , the server will then do some processing and then return the latest audits to keep themselves up to date.

I can't seem to get to a generic pattern that will work across the board for all of my models:

public class Domain {
    public int Id { get; set; }
    public string Property1 { get; set; }
    public int Property2 { get; set; }
}

Then I think I want to be able to do something like so:

public class DomainContext : DbContext {
    public DbSet<Domain> Domain { get; set; }
    public DbSet<History<Domain>> DomainHistory { get; set; }
}

This is my problem class taking this route, I want to inherit from Domain so things like property changes and EF migrations (in code first) will 'just work'. But I Cannot derive from 'T' because it is a type parameter

public class History<T> 
    : T //Cannot derive from 'T' because it is a type parameter
    where T : class {
    public DateTime CreatedOn { get; set; }
    public int CreatedByUserId { get; set; }
    public int EntityFK { get; set; }
    // This will always be the current version
    //public T Entity { get; set; }

    // I could store a snapshot of the state at the time of the audit
    public string XMLData { get; set; }
}

I don't know if my use of generics is warranted here but I'm basically trying to get to a point where I can do the below so my models play nicely with EF Migrations:

        Domain d = GetDomainModel();
        History<Domain> dh = new History<Domain>();

        dh.Property1 = d.Property1;
        dh.Property2 = d.Property2;

How can this be done?

For a basic audit of your entities you can use a base class and intercept the changue type in a override of savechangues in context, like this (sorry of format, i write in mobile):

public class AuditBase
{
    //Adapt your requirements, the propertys are exists in db
    public datetime creationdate { get; set; }
    public datetime modificationdate { get; set; }
    public string creationuser { get; set; }
    public string modificationuser { get; set; }
}

public class ModelBBDD : AuditBase
{ }

You can override the SaveChanges method of Context. In the method, you can through the ChangueTracker property of Database Class for added or updates dto's, like this:

var dto = entity as auditbase;
if (dto == null) continue;
if (dto.state == entitystate.added)
{
    ((Auditbase)entity).creationdate = datetime.now;
    ((Auditbase)entity).creationuser = environment.username;
}
else if( dto.state == entitystate.modified)
...
...

If you can log all the changues of properties, you can trough all the properties of dto with reflection and type in SaveChanges, and save values in log.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM