0

In my previous applications i have successfully set up an audit trail using Paul Van Bladel's approach. His approach worked perfectly and was extremely easy to follow. However, he's only using a single table to store the audited records. I need to do something similar except i need to have an audit table for each of the tables that will be audited which is about 7-8 tables. If i could figure out how to pass generic table objects i could possibly recuse Paul Van Bladel's solution. Is anyone aware of any other examples online i could possible refer to? Or any suggestions on how to properly implement an audit trailing for multiple tables.

p.s I tried using Beth Massi's example but it seems it wasn't meant to be used in VS2012 Lightswitch as it doesn't work out of the box?

HiTech
  • 913
  • 1
  • 16
  • 34

2 Answers2

0

Your question is incredibly broad, potentially too broad. From what I'm gathering though you have several tables, more than likely with different columns. Your looking for a generic approach, to simply write the proper content based on the column without too much code reproduction.

What you could and should do:

  • Write out those tables.
  • Determine the content that is required to be audited.
  • Compare those tables too each other.

That often helps me determine to what degree content should be abstracted. This particular example may benefit from Inversion Of Control or Dependency Injection. This way you can inject particular audit's to particular Classes.

public interface IAudit<T>
{
     void WriteToAudit(<T> model);
}

So this particular Interface will implement a Generic, which should represent your audit data model. Which can provide several differentiating models to better suite your requirements, while providing flexibility.

Now you would need to write your implementation classes, which inherit the interface.

public class Inventory : IAudit<InventoryModel>
{
     public void WriteToAudit(InventoryModel model)
     {
          // Write your database content, then pass *Properties* from the model.
          // Which will write for this particular table.
     }
}

Now the powerful part of this approach:

public class Stuff
{
     private IAudit audit;
     public void DoSomething(model)
     {
          audit.WriteToAudit(model);
     }
}

So now you could essentially create a new IAudit, then you can pass is through several approaches:

  • Constructor
  • Method

This is an incredibly rough implementation and I may have several typos. This was a quick post, but hopefully this points you in the proper direction. More detail on the matter can be found here.

Greg
  • 11,302
  • 2
  • 48
  • 79
  • I have to admit, I'm having some trouble integrating this with Lightswitch. Part of it is my lack of experince with Interfaces and Generics. Do you have any guidance on how i can use this with Lightswitch? – HiTech Oct 20 '14 at 16:46
  • I've never used Light Switch sorry. – Greg Oct 20 '14 at 18:23
0

One option you could consider is updating your table structures to provide row-versioning as an alternative to an external audit table. This pattern is very helpful when you need a full audit trail and the ability to perform data lineage analysis. The other benefit of this is reporting - you can interrogate the state of a given record at a given point in time - very helpful for creating fact tables or preserving state on slowly changing dimensions. My preferred approach for this is to use something along the lines of an SCD Type 2 pattern. (See here for the general idea.)

For each table on which you implement this pattern, modify the default query to only return the active record - i.e. filter for DateTo IS NULL. Then all you need to do is intercept the standard CRUD events for Delete and Update as follows: Table_Updating():

  1. Copy the updated entity (containing all of the changes) into a new local entity record object. (e.g. Order object) Make sure the ToDate field is null and the FromDate is DateTime.Now
  2. Add the local entity to the Entity collection using it's Add method (e.g. add new Order object to the Orders collection using the Orders.Add(newOrder) method.
  3. Get a hook to the existing copy of the entity record. (i.e. get Order object matching the target OrderID where ToDate Is NULL)
  4. Update the existing copy of the entity record and set the ToDate to DateTime.Now
  5. Commit the changes

Table_Deleting():

  1. Update the ToDate on the target record to DateTime.Now instead of NULL
  2. Remove the entity from the collection of changed entities
  3. Commit the changes

Table_Inserting():

  1. Make sure that the DateFrom field is set to DateTime.Now, the DateTo field is NULL
  2. Commit the changes.

That's it.

Ozziemedes
  • 311
  • 1
  • 6