/// <summary>
        /// Registers and type for auditing.
        /// </summary>
        /// <param name="auditableEntityType">Type to audit, must implement IAuditableEntity.</param>
        /// <param name="auditEntityType">Type of audit entity, must implement IAuditEntity.</param>
        public static void RegisterAuditType(Type auditableEntityType, Type auditEntityType)
        {
            // Basic parameter validation.
            if (auditableEntityType == null)
            {
                throw new ArgumentNullException("auditableEntityType");
            }

            if (auditTypes.ContainsKey(auditableEntityType))
            {
                throw new ArgumentException("Type already registered for auditing.", "auditableEntityType");
            }

            // Validate the entity.
            var iface = auditableEntityType.GetInterface("IAuditableEntity");

            if (iface == null)
            {
                throw new ArgumentException("Entity does implement IAuditableEntity", "auditableEntityType");
            }

            AuditTypeInfo info = new AuditTypeInfo {
                EntityType = auditableEntityType, AuditEntityType = auditEntityType
            };

            // Validate the auditEntity
            if (auditEntityType != null)
            {
                iface = auditEntityType.GetInterface("IAuditEntity");
                if (iface == null)
                {
                    throw new ArgumentException("Entity does implement IAuditEntity", "auditEntityType");
                }

                // Extract the list of properties to audit.
                var properties       = auditEntityType.GetProperties();
                var entityProperties = auditableEntityType.GetProperties().ToDictionary(x => x.Name);
                foreach (var property in properties)
                {
                    if (entityProperties.ContainsKey(property.Name))
                    {
                        if (property.PropertyType == entityProperties[property.Name].PropertyType)
                        {
                            info.AuditProperties.Add(property.Name);
                        }
                    }
                }
            }

            // Valid so register.
            auditTypes.Add(auditableEntityType, info);
        }
        /// <summary>
        /// Checks the destination object for complex types. Returns a list of fields that are complex types.
        /// </summary>
        /// <param name="auditTypeInfo"></param>
        /// <param name="entityEntry"></param>
        /// <returns></returns>
        private ICollection <string> GetComplexTypes(AuditTypeInfo auditTypeInfo, DbEntityEntry entityEntry)
        {
            var returnValue = new List <string>();

            foreach (string propertyName in auditTypeInfo.AuditProperties)
            {
                if (entityEntry.Property(propertyName).GetType().Name.Contains("DbComplexPropertyEntry"))
                {
                    returnValue.Add(propertyName);
                }
            }

            return(returnValue);
        }
        private IAuditEntity AuditEntity(DbEntityEntry entityEntry, AuditTypeInfo auditTypeInfo, DateTimeOffset auditDateTime, string user)
        {
            // Create audit entity.
            DbSet        set         = this.Set(auditTypeInfo.AuditEntityType);
            IAuditEntity auditEntity = set.Create() as IAuditEntity;

            // Check audit entity for complex types.
            var complexTypes = GetComplexTypes(auditTypeInfo, entityEntry);

            //Instantiate complex types.
            foreach (var field in complexTypes)
            {
                var property   = auditEntity.GetType().GetProperty(field);
                var entityType = property.PropertyType;
                property.SetValue(auditEntity, Activator.CreateInstance(entityType));
            }

            //Attach audit Entity to the context.
            set.Add(auditEntity);

            // Copy the properties.
            DbEntityEntry auditEntityEntry = this.Entry(auditEntity);

            foreach (string propertyName in auditTypeInfo.AuditProperties)
            {
                auditEntityEntry.Property(propertyName).CurrentValue = entityEntry.Property(propertyName).OriginalValue;
            }

            // Set the audit columns.
            auditEntityEntry.Property(AuditUpdatedColumnName).CurrentValue  = auditDateTime;
            auditEntityEntry.Property(AuditUserColumnName).CurrentValue     = user;
            auditEntityEntry.Property(AuditTypeColumnName).CurrentValue     = entityEntry.State == EntityState.Modified ? "update" : "delete";
            auditEntityEntry.Property(AuditSourceIdColumnName).CurrentValue = entityEntry.OriginalValues.GetValue <int>("Id");

            return(auditEntity);
        }