I'm the the process of adding change auditing to my existing `DB` class which encapsulates database calls.

Previously I would just pass in a `String` and a `SqlParameter` array but now I've added the class 'DBData' to contain the values required for the auditing.

I'm not sure whether passing in this `DBData` object and then calling `AuditAction()` is the cleanest way to organise the code though and would appreciate input.

```
public class DBData
{
    public DBData() { }
    public DBData(object newValue, object oldValue)
    {
        this.NewValue = newValue;
        this.OldValue = oldValue;
    }

    public int UserKey { get; set; }
    public object NewValue { get; set; }
    public object OldValue { get; set; }

    public string Query { get; set; }
    public SqlParameter[] Parameters { get; set; }
}

public static class DB
{
    /// <summary>
    /// Connection String to Local Machines Database
    /// </summary>
    private static readonly string connectionString   = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
    private static readonly DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");

    public static void Update(DBData data)
    {
        try
        {
            AuditAction(data.UserKey, data.NewValue, data.OldValue);
            InsertData(data.Query, data.Parameters);
        }
        catch (Exception)
        {

            throw;
        }
    }

    /// <summary>
    /// Inserts data into the database
    /// </summary>
    /// <param name="sql">query</param>
    /// <param name="parameters">declared parameters</param>
    public static void InsertData(string sql, SqlParameter[] parameters)
    {
        try
        {
            using (DbConnection connection = factory.CreateConnection())
            {
                connection.ConnectionString = connectionString;

                using (DbCommand command = factory.CreateCommand())
                {
                    command.Connection = connection;
                    command.CommandType = CommandType.Text;
                    command.CommandText = sql;

                    if (parameters != null)
                    {
                        foreach (var parameter in parameters)
                        {
                            if (parameter != null)
                                command.Parameters.Add(parameter);
                        }
                    }
                    connection.Open();
                    command.ExecuteNonQuery();
                }
            }
        }
        catch (Exception)
        {
            throw;
        }
    }

    /// <summary>
    /// Compare two objects and log the properties which have changed to the database.
    /// </summary>
    /// <param name="userKey">id of logged in user</param>
    /// <param name="newObject">object with changes</param>
    /// <param name="oldObject">copy of object before changes</param>
    public static void AuditAction(int userKey, object newObject, object oldObject)
    {
        try
        {
            ChangeLogger logger = new ChangeLogger(userKey, newObject, oldObject);

            // The name of the object should give a good idication of what the change was from
            // E.g. ScanSchedule is obviously a change to the scan schedule
            string className = newObject.GetType().Name; 

            logger.Audit();
            if (!logger.Success)
            {
                throw logger.Exception;
            }

            foreach (ChangeLog log in logger.Changes)
            {
                LogAction(log.ObjectId, log.ValueNew, log.ValueOld, log.Property, className, DateTime.Now);
            }
        }
        catch (Exception)
        {
            throw;
        }
    }

    /// <summary>
    /// Insert data into the ChangeLog table of the database.
    /// </summary>
    /// <param name="userKey">id of user who made the change</param>
    /// <param name="valueNew">changed value</param>
    /// <param name="valueOld">value before change</param>
    /// <param name="property">property being changed</param>
    /// <param name="className">class where change took place</param>
    /// <param name="changeDate">time change made</param>
    private static void LogAction(long userKey, string valueNew, string valueOld, string property, string className, DateTime changeDate)
    {
        try
        {
            string insertLog
                = "INSERT INTO ChangeLog "
                + "(UserKey, ObjectName, Property, NewValue, PreviousValue, ChangeDate) "
                + "VALUES "
                + "(@UserKey, @ObjectName, @Property, @NewValue, @PreviousValue, @ChangeDate)";

            DB.InsertData(insertLog,
                new[]
                {
                    new SqlParameter("@UserKey", userKey),
                    new SqlParameter("@ObjectName", className),
                    new SqlParameter("@Property", property),
                    new SqlParameter("@NewValue", valueNew),
                    new SqlParameter("@PreviousValue", valueOld),
                    new SqlParameter("@ChangeDate", changeDate),
                });
        }
        catch (Exception)
        {
            throw;
        }
    }
}

```

Example of use:

```
private static void UpdateScanSchedule(DBData data, ScanSchedule schedule)
{
    try
    {
        data.Query
            = "UPDATE ScanSchedules " 
            + "SET GroupID = @GroupID, ScheduleType =@ScheduleType, " 
            + "RunDays =@RunDays ,RunDate =@RunDate, Description = @Description, " 
            + "RunTime = @RunTime, Ranges = @Ranges , Devices = @Devices, Excluded = @Excluded " 
            + "WHERE ScanScheduleID = @ScanScheduleID";

        data.Parameters
            = new[]
            {
                new SqlParameter("@GroupID", schedule.GroupID),
                new SqlParameter("@ScheduleType", schedule.ScheduleType),
                new SqlParameter("@RunDays", schedule.RunDays),
                new SqlParameter("@RunDate", schedule.RunDate),
                new SqlParameter("@Description", schedule.Description),
                new SqlParameter("@RunTime", schedule.RunTime),
                new SqlParameter("@Ranges", schedule.Ranges),
                new SqlParameter("@Devices", schedule.Devices),
                new SqlParameter("@Excluded", schedule.Excluded),
                new SqlParameter("@ScanScheduleID", schedule.ScanScheduleID),
            };

        DB.Update(data);
    }
    catch (Exception)
    {

        throw;
    }
}

private static void Example(ScanSchedule oldSchedule, int userKey)
{
    try
    {
        ScanSchedule schedule   = new ScanSchedule();
        schedule.GroupID        = GroupID;
        schedule.Description    = Description;
        schedule.Devices        = Util.ValidIPAddressList(Devices);
        schedule.Excluded       = Util.ValidIPAddressList(Excluded);
        schedule.Ranges         = Ranges;
        schedule.RunDate        = RunDate;
        schedule.RunDays        = RunDays;
        schedule.RunTime        = DateTime.Parse(ScanTime);
        schedule.ScanScheduleID = ScanScheduleID;
        schedule.ScheduleType   = ScheduleType;

        UpdateScanSchedule(new DBData(schedule, oldSchedule, userKey), schedule);
    }
    catch (Exception)
    {
        throw;
    }
}

```