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;
}
}