web-dev-qa-db-fra.com

comment créer une piste d'audit avec Entity Framework 5 et MVC 4

Je crée une application MVC 4, en utilisant EF 5. Je dois faire une piste d'audit, c'est-à-dire enregistrer toutes les modifications apportées par les utilisateurs finaux.

J'ai posé cette question à quelques reprises, mais je n'ai pas vraiment obtenu de réponse satisfaisante auparavant. J'ajoute donc beaucoup plus de détails dans l'espoir d'arriver quelque part ..

actuellement j'ai plusieurs référentiels

c'est à dire

 public class AuditZoneRepository : IAuditZoneRepository
    {
        private AISDbContext context = new AISDbContext();


        public int Save(AuditZone model, ModelStateDictionary modelState)
        {
            if (model.Id == 0)
            {
                context.AuditZones.Add(model);
            }
            else
            {
                var recordToUpdate = context.AuditZones.FirstOrDefault(x => x.Id == model.Id);
                if (recordToUpdate != null)
                {
                    recordToUpdate.Description = model.Description;
                    recordToUpdate.Valid = model.Valid;
                    recordToUpdate.ModifiedDate = DateTime.Now;
                }
            }

            try
            {
                context.SaveChanges();
                return 1;
            }
            catch (Exception ex)
            {
                modelState.AddModelError("", "Database error has occured.  Please try again later");
                return -1;
            }
        }
    }



    public class PostcodesRepository : IPostcodesRepository
    {
        private AISDbContext context = new AISDbContext();


        public int Save(Postcodes model, ModelStateDictionary modelState)
        {
            if (model.Id == 0)
            {
                context.Postcodes.Add(model);
            }
            else
            {
                var recordToUpdate = context.Postcodes.FirstOrDefault(x => x.Id == model.Id);
                if (recordToUpdate != null)
                {
                    recordToUpdate.Suburb = model.Suburb;
                    recordToUpdate.State = model.State;
                    recordToUpdate.Postcode = model.Postcode;
                    recordToUpdate.AuditZoneId = model.AuditZoneId;
                    recordToUpdate.ModifiedDate = DateTime.Now;
                }
            }

            try
            {
                context.SaveChanges();
                return 1;
            }
            catch (Exception ex)
            {
                modelState.AddModelError("", "Database error has occured.  Please try again later");
                return -1;
            }
        }



    }

Maintenant, je sais pour moi d'ajouter le code pour vérifier s'il y a des changements dont j'ai besoin pour l'ajouter lors de la sauvegarde. Avant le context.SaveChanges ().

Mais actuellement, j'ai 10 repos. Je ne veux pas vraiment ajouter de code à 10 endroits différents. Comme ce code fera exactement la même chose. Je veux en quelque sorte avoir une classe de base dont les repos héritent.

de l'aide? un exemple de code? des pointeurs?

serait apprécié. Je suis sûr que d'autres personnes l'auraient fait avant

Je mappe mes clés, mes relations et mes tables comme ça

 public class AuditZoneMap : EntityTypeConfiguration<AuditZone>
    {
        public AuditZoneMap()
        {
            // Primary Key
            HasKey(t => t.Id);


            // Properties
            Property(t => t.Description)
                .HasMaxLength(100);


            // Table & Column Mappings
            ToTable("AuditZone");
            Property(t => t.Id).HasColumnName("Id");
            Property(t => t.Description).HasColumnName("Description");
            Property(t => t.Valid).HasColumnName("Valid");          
            Property(t => t.CreatedDate).HasColumnName("CreatedDate");
            Property(t => t.CreatedBy).HasColumnName("CreatedBy");
            Property(t => t.ModifiedDate).HasColumnName("ModifiedDate");
            Property(t => t.ModifiedBy).HasColumnName("ModifiedBy");

            // Relationships        
            HasOptional(t => t.CreatedByUser)
               .WithMany(t => t.CreatedByAuditZone)
               .HasForeignKey(d => d.CreatedBy);

            HasOptional(t => t.ModifiedByUser)
                .WithMany(t => t.ModifiedByAuditZone)
                .HasForeignKey(d => d.ModifiedBy);


        }
    }
20
user2206329

Ce que je vous recommande est d'utiliser la propriété ChangeTracker dans EF.

Dans votre DBContext.cs, vous aurez ceci:

public class DBContext : DbContext
    {

        public DBContext () : base("DatabaseName")
        {

        }



        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {


        }

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



        // This is overridden to prevent someone from calling SaveChanges without specifying the user making the change
        public override int SaveChanges()
        {
            throw new InvalidOperationException("User ID must be provided");
        }
        public int SaveChanges(int userId)
        {
            // Get all Added/Deleted/Modified entities (not Unmodified or Detached)
            foreach (var ent in this.ChangeTracker.Entries().Where(p => p.State == System.Data.EntityState.Added || p.State == System.Data.EntityState.Deleted || p.State == System.Data.EntityState.Modified))
            {
                // For each changed record, get the audit record entries and add them
                foreach (AuditLog x in GetAuditRecordsForChange(ent, userId))
                {
                    this.AuditLogs.Add(x);
                }
            }

            // Call the original SaveChanges(), which will save both the changes made and the audit records
            return base.SaveChanges();
        }

        private List<AuditLog> GetAuditRecordsForChange(DbEntityEntry dbEntry, int userId)
        {
            List<AuditLog> result = new List<AuditLog>();

            DateTime changeTime = DateTime.UtcNow;

            // Get the Table() attribute, if one exists
            //TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;

            TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), true).SingleOrDefault() as TableAttribute;

            // Get table name (if it has a Table attribute, use that, otherwise get the pluralized name)
            string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;

            // Get primary key value (If you have more than one key column, this will need to be adjusted)
            var keyNames = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).ToList();

            string keyName = keyNames[0].Name; //dbEntry.Entity.GetType().GetProperties().Single(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).Name;

            if (dbEntry.State == System.Data.EntityState.Added)
            {
                // For Inserts, just add the whole record
                // If the entity implements IDescribableEntity, use the description from Describe(), otherwise use ToString()

                foreach (string propertyName in dbEntry.CurrentValues.PropertyNames)
                {
                    result.Add(new AuditLog()
                    {
                        AuditLogId = Guid.NewGuid(),
                        UserId = userId,
                        EventDateUTC = changeTime,
                        EventType = "A",    // Added
                        TableName = tableName,
                        RecordId = dbEntry.CurrentValues.GetValue<object>(keyName).ToString(),
                        ColumnName = propertyName,
                        NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
                    }
                            );
                }
            }
            else if (dbEntry.State == System.Data.EntityState.Deleted)
            {
                // Same with deletes, do the whole record, and use either the description from Describe() or ToString()
                result.Add(new AuditLog()
                {
                    AuditLogId = Guid.NewGuid(),
                    UserId = userId,
                    EventDateUTC = changeTime,
                    EventType = "D", // Deleted
                    TableName = tableName,
                    RecordId = dbEntry.OriginalValues.GetValue<object>(keyName).ToString(),
                    ColumnName = "*ALL",
                    NewValue = (dbEntry.OriginalValues.ToObject() is IDescribableEntity) ? (dbEntry.OriginalValues.ToObject() as IDescribableEntity).Describe() : dbEntry.OriginalValues.ToObject().ToString()
                }
                    );
            }
            else if (dbEntry.State == System.Data.EntityState.Modified)
            {
                foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
                {
                    // For updates, we only want to capture the columns that actually changed
                    if (!object.Equals(dbEntry.OriginalValues.GetValue<object>(propertyName), dbEntry.CurrentValues.GetValue<object>(propertyName)))
                    {
                        result.Add(new AuditLog()
                        {
                            AuditLogId = Guid.NewGuid(),
                            UserId = userId,
                            EventDateUTC = changeTime,
                            EventType = "M",    // Modified
                            TableName = tableName,
                            RecordId = dbEntry.OriginalValues.GetValue<object>(keyName).ToString(),
                            ColumnName = propertyName,
                            OriginalValue = dbEntry.OriginalValues.GetValue<object>(propertyName) == null ? null : dbEntry.OriginalValues.GetValue<object>(propertyName).ToString(),
                            NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
                        }
                            );
                    }
                }
            }
            // Otherwise, don't do anything, we don't care about Unchanged or Detached entities

            return result;
        }


    }

Cela utilisera le tableau suivant dans votre base de données:

USE [databasename]
GO

/****** Object:  Table [dbo].[auditlog]    Script Date: 06/01/2014 05:56:49 p. m. ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[auditlog](
    [auditlogid] [uniqueidentifier] NOT NULL,
    [userid] [int] NOT NULL,
    [eventdateutc] [datetime] NOT NULL,
    [eventtype] [char](1) NOT NULL,
    [tablename] [nvarchar](100) NOT NULL,
    [recordid] [nvarchar](100) NOT NULL,
    [columnname] [nvarchar](100) NOT NULL,
    [originalvalue] [nvarchar](max) NULL,
    [newvalue] [nvarchar](max) NULL,
 CONSTRAINT [PK_AuditLog] PRIMARY KEY NONCLUSTERED 
(
    [auditlogid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[auditlog]  WITH CHECK ADD  CONSTRAINT [FK_auditlog_users] FOREIGN KEY([userid])
REFERENCES [dbo].[users] ([userid])
GO

ALTER TABLE [dbo].[auditlog] CHECK CONSTRAINT [FK_auditlog_users]
GO

Avec tout cela, vous n'aurez qu'à appeler votre dbContext.SaveChanges (ici le userId);

J'espère que cela fonctionnera pour vous ... Je l'utilise dans toutes mes applications et fonctionne très bien!

Profitez-en.


Code complet trouvé ici: https://jmdority.wordpress.com/2011/07/20/using-entity-framework-4-1-dbcontext-change-tracking-for-audit-logging/

24
VAAA

J'ai trouvé ce package NuGet ( TrackerEnabledDbContext ) et j'ai suivi ces 4 étapes:

  1. Installer le package TrackerEnabledDbContext

  2. Hériter mon DbContext de TrackerContext dans l'espace de noms TrackerEnabledDbContext

    public class ApplicationDbContext :  TrackerContext 
        {
            public ApplicationDbContext()
                : base("DefaultConnection")
            {
            }
    

Ajouter une migration et mettre à jour ma base de données. Deux nouvelles tables ont été créées pour enregistrer les modifications (AuditLog et AuditLogDetails).

  1. Décidez quelles tables vous souhaitez suivre et appliquez l'attribut [TrackChanges] Aux classes. Si vous souhaitez ignorer le suivi de certaines colonnes spécifiques, vous pouvez appliquer l'attribut [SkipTracking] À ces colonnes (propriétés).

  2. Chaque fois que vous effectuez une modification dans la base de données, vous appelez DbContext.SaveChanges(). Vous avez maintenant une surcharge disponible pour ce qui prend un entier. Il doit s'agir de l'ID utilisateur de la personne connectée. Si vous ne transmettez pas l'ID utilisateur, cette modification ne sera pas enregistrée dans la table de suivi.

    databaseContext.SaveChanges(userId);
    

Et c'est tout. Plus tard, vous pouvez récupérer les journaux avec ceci:

var AuditLogs = db.GetLogs<Proyecto>(id).ToList();
8
demispb

Avertissement : Je suis le propriétaire du projet Entity Framework Plus

EF + possède des fonctionnalités d'audit qui prennent en charge EF5, EF6 et EF Core.

// using Z.EntityFramework.Plus; // Don't forget to include this.

var ctx = new EntityContext();
// ... ctx changes ...

var audit = new Audit();
audit.CreatedBy = "ZZZ Projects"; // Optional
ctx.SaveChanges(audit);

// Access to all auditing information
var entries = audit.Entries;
foreach(var entry in entries)
{
    foreach(var property in entry.Properties)
    {
    }
}

De nombreuses options sont disponibles comme une sauvegarde automatique dans la base de données.

Documentation: EF + Audit

3
Jonathan Magnan

Dans le modèle de référentiel générique, nous pouvons écrire un gestionnaire d'événements générique pour l'événement savechanges de contexte db.

Je l'ai googlé et j'ai rassemblé peu d'informations.

  1. Je ne veux pas écrire de déclencheur de serveur SQL
  2. Je ne veux pas gérer la méthode savechanges dans chaque entité.

Je prévois donc d'écrire une méthode générique unique

Structure DB que j'utilise

table d'audit

CREATE TABLE [dbo].[Audit](
    [Id] [BIGINT] IDENTITY(1,1) NOT NULL,
    [TableName] [nvarchar](250) NULL,
    [Updated By] [nvarchar](100) NULL,
    [Actions] [nvarchar](25) NULL,
    [OldData] [text] NULL,
    [NewData] [text] NULL,
    [Created For] varchar(200) NULL,
    [Updated Date] [datetime] NULL,
 CONSTRAINT [PK_DBAudit] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

2.Mettez à jour votre dbcontext avec l'entité de table d'audit.

3.Hook gestionnaire d'événements générique pour les changements de Dbcontext

code c #

    namespace ARMS.Domain      
    {
        using System;
        using System.Collections.Generic;
        using System.Collections.ObjectModel;
        using System.Data;
        using System.Data.Objects;
        using System.Linq;
        using System.Text;
        using System.ComponentModel.DataAnnotations;
        public partial class ARMSContext
        {
            Collection<Audit> auditTrailList = new Collection<Audit>();

            partial void OnContextCreated()
            { 
                this.SavingChanges += new EventHandler(ArmsEntities_SavingChanges);
            }
            public enum AuditActions
            {
                Added,
                Modified,
                Deleted
            }
            void ArmsEntities_SavingChanges(object sender, EventArgs e)
            { 
                auditTrailList.Clear(); 
                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 Audit))
                        {
                            Audit audit = this.GetAudit(stateEntryEntity);
                            auditTrailList.Add(audit);
                        }



                }
                if (auditTrailList.Count > 0)
                {
                    foreach (var audit in auditTrailList)
                    {
                        this.Audits.AddObject(audit);  
                    } 
                }
            }
            public Audit GetAudit(ObjectStateEntry entry)
            {
                Audit audit = new Audit();



                audit.Updated_By ="Test";
                audit.TableName = entry.EntitySet.ToString();
                audit.Updated_Date = DateTime.Now;
                audit.Created_For = Convert.ToString(entry.Entity);
                audit.Actions = Enum.Parse(typeof(AuditActions),entry.State.ToString(), true).ToString();
                StringBuilder newValues = new StringBuilder();
                StringBuilder oldValues = new StringBuilder();
                if (entry.State == EntityState.Added)
                {  
                    SetAddedProperties(entry, newValues);
                    audit.NewData = newValues.ToString();  
                } 
                else if (entry.State == EntityState.Deleted)
                {   SetDeletedProperties(entry, oldValues);
                    audit.OldData = oldValues.ToString(); 
                } 
                else if (entry.State == EntityState.Modified)
                { 
                    SetModifiedProperties(entry, oldValues, newValues);
                    audit.OldData = oldValues.ToString();
                    audit.NewData = newValues.ToString(); 
                } 
                return audit;
            } 
            private void SetAddedProperties(ObjectStateEntry entry, StringBuilder newData)
            {      
                CurrentValueRecord currentValues = entry.CurrentValues;
                for (int i = 0; i < currentValues.FieldCount; i++)
                {  
                    newData.AppendFormat("{0}={1} || ", currentValues.GetName(i), currentValues.GetValue(i));
                } 
            } 
            private void SetDeletedProperties(ObjectStateEntry entry, StringBuilder oldData)
            {
                foreach (var propertyName in entry.GetModifiedProperties())
                {
                    var oldVal = entry.OriginalValues[propertyName];
                    if (oldVal != null)
                    {
                        oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
                    }
                }
            } 
            private void SetModifiedProperties(ObjectStateEntry entry, StringBuilder oldData, StringBuilder newData)
            {         
                foreach (var propertyName in entry.GetModifiedProperties())
                {
                    var oldVal = entry.OriginalValues[propertyName];
                    var newVal = entry.CurrentValues[propertyName];
                    if (oldVal != null && newVal != null && !Equals(oldVal, newVal))
                    {
                        newData.AppendFormat("{0}={1} || ", propertyName, newVal);
                        oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
                    }
                } 
            }   
        }
    }
2

Créez une classe pour capturer les modifications ou suivre les modifications lorsqu'une entité est ajoutée, modifiée ou supprimée.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Web;

namespace MVC_AuditTrail.Models
{
    public class AuditTrailFactory
    {
        private DbContext context;

        public AuditTrailFactory(DbContext context)
        {
            this.context = context;
        }
        public Audit GetAudit(DbEntityEntry entry)
        {
            Audit audit = new Audit();
            // var user = (User)HttpContext.Current.Session[":user"];
            audit.UserId = "swapnil";// user.UserName;
            audit.TableName = GetTableName(entry);
            audit.UpdateDate = DateTime.Now;
            audit.TableIdValue = GetKeyValue(entry);

            //entry is Added 
            if (entry.State == EntityState.Added)
            {
                var newValues = new StringBuilder();
                SetAddedProperties(entry, newValues);
                audit.NewData = newValues.ToString();
                audit.Actions = AuditActions.I.ToString();
            }
            //entry in deleted
            else if (entry.State == EntityState.Deleted)
            {
                var oldValues = new StringBuilder();
                SetDeletedProperties(entry, oldValues);
                audit.OldData = oldValues.ToString();
                audit.Actions = AuditActions.D.ToString();
            }
            //entry is modified
            else if (entry.State == EntityState.Modified)
            {
                var oldValues = new StringBuilder();
                var newValues = new StringBuilder();
                SetModifiedProperties(entry, oldValues, newValues);
                audit.OldData = oldValues.ToString();
                audit.NewData = newValues.ToString();
                audit.Actions = AuditActions.U.ToString();
            }

            return audit;
        }

        private void SetAddedProperties(DbEntityEntry entry, StringBuilder newData)
        {
            foreach (var propertyName in entry.CurrentValues.PropertyNames)
            {
                var newVal = entry.CurrentValues[propertyName];
                if (newVal != null)
                {
                    newData.AppendFormat("{0}={1} || ", propertyName, newVal);
                }
            }
            if (newData.Length > 0)
                newData = newData.Remove(newData.Length - 3, 3);
        }

        private void SetDeletedProperties(DbEntityEntry entry, StringBuilder oldData)
        {
            DbPropertyValues dbValues = entry.GetDatabaseValues();
            foreach (var propertyName in dbValues.PropertyNames)
            {
                var oldVal = dbValues[propertyName];
                if (oldVal != null)
                {
                    oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
                }
            }
            if (oldData.Length > 0)
                oldData = oldData.Remove(oldData.Length - 3, 3);
        }

        private void SetModifiedProperties(DbEntityEntry entry, StringBuilder oldData, StringBuilder newData)
        {
            DbPropertyValues dbValues = entry.GetDatabaseValues();
            foreach (var propertyName in entry.OriginalValues.PropertyNames)
            {
                var oldVal = dbValues[propertyName];
                var newVal = entry.CurrentValues[propertyName];
                if (oldVal != null && newVal != null && !Equals(oldVal, newVal))
                {
                    newData.AppendFormat("{0}={1} || ", propertyName, newVal);
                    oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
                }
            }
            if (oldData.Length > 0)
                oldData = oldData.Remove(oldData.Length - 3, 3);
            if (newData.Length > 0)
                newData = newData.Remove(newData.Length - 3, 3);
        }

        public long? GetKeyValue(DbEntityEntry entry)
        {
            var objectStateEntry = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
            long id = 0;
            if (objectStateEntry.EntityKey.EntityKeyValues != null)
                id = Convert.ToInt64(objectStateEntry.EntityKey.EntityKeyValues[0].Value);

            return id;
        }

        private string GetTableName(DbEntityEntry dbEntry)
        {
            TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
            string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
            return tableName;
        }
    }

    public enum AuditActions
    {
        I,
        U,
        D
    }
}

Créez ensuite une entité de table d'audit et une classe de contexte.

Et remplacer la méthode savechanges dans cette méthode permet d'obtenir les modifications d'audit et de les enregistrer avant que l'entité de base ne soit enregistrée.

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web;

namespace MVC_AuditTrail.Models
{
    public class Student
    {
        public int StudentID { get; set; }

        public string Name { get; set; }

        public string  mobile { get; set; }
    }

    public  class Audit
    {
        public long Id { get; set; }
        public string TableName { get; set; }
        public string UserId { get; set; }
        public string Actions { get; set; }
        public string OldData { get; set; }
        public string NewData { get; set; }
        public Nullable<long> TableIdValue { get; set; }
        public Nullable<System.DateTime> UpdateDate { get; set; }
    }


    public class StdContext : DbContext
    {
        private AuditTrailFactory auditFactory;
        private List<Audit> auditList = new List<Audit>();
        private List<DbEntityEntry> objectList = new List<DbEntityEntry>();
        public StdContext() : base("stdConnection")
        {
            Database.SetInitializer<StdContext>(new CreateDatabaseIfNotExists<StdContext>());
        }

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

        public override int SaveChanges()
        {
            auditList.Clear();
            objectList.Clear();
            auditFactory = new AuditTrailFactory(this);

            var entityList = ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Deleted || p.State == EntityState.Modified);
            foreach (var entity in entityList)
            {
                Audit audit = auditFactory.GetAudit(entity);
                bool isValid = true;
                if (entity.State == EntityState.Modified && string.IsNullOrWhiteSpace(audit.NewData) && string.IsNullOrWhiteSpace(audit.OldData))
                {
                    isValid = false;
                }
                if (isValid)
                {
                    auditList.Add(audit);
                    objectList.Add(entity);
                }
            }

            var retVal = base.SaveChanges();
            if (auditList.Count > 0)
            {
                int i = 0;
                foreach (var audit in auditList)
                {
                    if (audit.Actions == AuditActions.I.ToString())
                        audit.TableIdValue = auditFactory.GetKeyValue(objectList[i]);
                    this.Audit.Add(audit);
                    i++;
                }

                base.SaveChanges();
            }

            return retVal;
        }
    }
}
1
Swapnil Malap
  public override int SaveChanges()
        {
            var auditEntries = new List<AuditEntry>();

            var modifiedEntities = ChangeTracker.Entries()
                .Where(p => p.State == EntityState.Modified).ToList();

            foreach (var change in modifiedEntities)
            {
                var auditEntry = new AuditEntry(change);
                var primaryKey = GetPrimaryKeys(change);
                auditEntry.TableName = change.Entity.GetType().Name;//get table name
               // var id = change.CurrentValues.GetValue<object>("Id").ToString();//get current id
                auditEntry.EntityId = primaryKey.ToString();
                auditEntry.EntityTypeId = primaryKey.ToString();
                auditEntries.Add(auditEntry);


                foreach (var prop in change.OriginalValues.PropertyNames)
                {
                    if (prop == "Id")
                    {
                        continue;
                    }

                    switch (change.State)
                    {
                        case EntityState.Modified:
                            if ((change.State & EntityState.Modified) != 0)
                            {
                                auditEntry.OldValues[prop] = change.OriginalValues[prop].ToString();
                                auditEntry.NewValues[prop] = change.CurrentValues[prop].ToString();
                            }
                            break;
                    }

                }
                foreach (var auditEntry1 in auditEntries.Where(_ => !_.HasTemporaryProperties))
                {
                    Audits.Add(auditEntry1.ToAudit());
                }
            }
            return base.SaveChanges();
        }

        private object GetPrimaryKeys(DbEntityEntry entry)
        {
            var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);

            return objectStateEntry.EntityKey.EntityKeyValues[0].Value;

        }
0
Dimand