Log di controllo di Entity Framework 7

asp.net-core audit c# entity-framework-core

Domanda

Sto trasferendo un vecchio progetto su ASP.NET 5 e Entity Framework 7. Ho usato il primo approccio del database (scaffold DNX) per creare il modello.

Il vecchio progetto è basato su Entity Framework 4 e il controllo di verifica è implementato sovrascrivendo il metodo SaveChanges di DbContext :

public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
    int? UserId = null;
    if (System.Web.HttpContext.Current != null) 
        UserId = (from user in Users.Where(u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name) select user.Id).SingleOrDefault();

    foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
    {
        Type EntityType = entry.Entity.GetType();

        PropertyInfo pCreated = EntityType.GetProperty("Created");
        PropertyInfo pCreatedById = EntityType.GetProperty("CreatedById");
        PropertyInfo pModified = EntityType.GetProperty("Modified");
        PropertyInfo pModifiedById = EntityType.GetProperty("ModifiedById");

        if (entry.State == EntityState.Added)
        {
            if (pCreated != null)
                pCreated.SetValue(entry.Entity, DateTime.Now, new object[0]);
            if (pCreatedById != null && UserId != null)
                pCreatedById.SetValue(entry.Entity, UserId, new object[0]);
        }
        if (pModified != null)
            pModified.SetValue(entry.Entity, DateTime.Now, new object[0]);
        if (pModifiedById != null && UserId != null)
            pModifiedById.SetValue(entry.Entity, UserId, new object[0]);
        }
    }

    return base.SaveChanges(options);
}

La mia domanda è, come posso implementarlo in Entity Framework 7? Devo prendere il primo approccio del codice?

Risposta popolare

Fondamentalmente hai due modi per ottenere questo:

Utilizzo dell'API ChangeTracker (EF 6+):

Questo è il modo in cui lo facciamo attualmente in EF 6 ed è ancora valido e funzionante per EF 7:

Innanzitutto devi assicurarti che le tue entità stiano implementando un'interfaccia comune per i campi di controllo:

public interface IAuditableEntity 
{
    int? CreatedById { get; set; }

    DateTime Created { get; set; }

    int? ModifiedById { get; set; }

    DateTime Modified { get; set; }
}


Quindi puoi sovrascrivere SaveChanges e aggiornare ogni campo comune con i valori di controllo:

public override int SaveChanges()
{
    int? userId = null;
    if (System.Web.HttpContext.Current != null)
        userId = (from user in Users.Where(u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name) select user.Id).SingleOrDefault();

    var modifiedEntries = ChangeTracker.Entries<IAuditableEntity>()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);

    foreach (EntityEntry<IAuditableEntity> entry in modifiedEntries)
    {
        entry.Entity.ModifiedById = UserId;
        entry.Entity.Modified = DateTime.Now;

        if (entry.State == EntityState.Added)
        {
            entry.Entity.CreatedById = UserId;
            entry.Entity.Created = DateTime.Now;
        }
    }

    return base.SaveChanges();
}


Usando EF 7 nuova funzione "Proprietà ombra":

Le proprietà shadow sono proprietà che non esistono nella classe entità. Il valore e lo stato di queste proprietà sono mantenuti puramente nel Change Tracker.

In altre parole, le colonne di controllo non saranno esposte sulle tue entità che sembra essere un'opzione migliore rispetto a quella sopra in cui devi includerle nelle tue entità.

Per implementare le proprietà shadow, devi prima configurarle sulle tue entità. Diciamo per esempio che hai un oggetto User che deve avere alcune colonne di controllo:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().Property<int>("CreatedById");

    modelBuilder.Entity<User>().Property<DateTime>("Created");

    modelBuilder.Entity<User>().Property<int>("ModifiedById");

    modelBuilder.Entity<User>().Property<DateTime>("Modified");
}


Una volta configurati, ora puoi accedervi con SaveChanges () e aggiornare i loro valori di conseguenza:

public override int SaveChanges()
{
    int? userId = null;
    if (System.Web.HttpContext.Current != null)
        userId = (from user in Users.Where(u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name) select user.Id).SingleOrDefault();

    var modifiedBidEntries = ChangeTracker.Entries<User>()
        .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);

    foreach (EntityEntry<User> entry in modifiedBidEntries)
    {
        entry.Property("Modified").CurrentValue = DateTime.UtcNow;
        entry.Property("ModifiedById").CurrentValue = userId;

        if (entry.State == EntityState.Added)
        {
            entry.Property("Created").CurrentValue = DateTime.UtcNow;
            entry.Property("CreatedById").CurrentValue = userId;
        }
    }

    return base.SaveChanges();
}


Pensieri finali:

Per implementare qualcosa come le colonne di controllo, prenderò l'approccio di Shadow Properties poiché questi sono problemi trasversali e non appartengono necessariamente ai miei oggetti di dominio, quindi farli implementare in questo modo manterrà gli oggetti del mio dominio belli e puliti.



Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché