views:

31

answers:

2

I've created an Audit table for an ASP.NET MVC application to track key changes and actions. I want to present the contents of this table to authorized users in an easily readable format on the view.

The Audit table is (simplified) like so:

ID (int) | StaffID (int) | Action (string) | Timestamp (datetime)
-----------------------------------------------------------------
1987     | 27            | Delete entry: 9 | 2010-02-22 12:30:12
1988     | 34            | Add user: 912   | 2010-02-22 12:48:19

So far I've just been presenting that using the default "List" view in MVC however we're getting towards the end of development and I'd like to tidy up this view a bit by showing staff names rather than StaffIDs.

Initially, I'm using the approach of creating a "hybrid model" that contains both Audit and Staff and passing that to the view:

public class AuditModel
{
  public AuditModel(List<Audit> AuditEntries, List<Staff> AllStaff)
  {
    this.Audit = AuditEntries;
    this.Staff = AllStaff;
  }

  public List<Audit> Audit { get; private set; }
  public List<Staff> Staff { get; private set; }
}  

[AcceptVerbs("GET")]
public ActionResult ViewAuditTrail()
{
  var Audit = (from a in db.Audits orderby a.Timestamp descending select a).ToList();
  var Staff = (from s in db.Staffs select s).ToList();
  return View(new AuditModel(Audit, Staff));
}

But that leads to messiness in the view:

<%
foreach (var Entry in Model.AuditEntries)
{
  var StaffDetails = Model.AllStaff.Where(s => s.ID == Entry.StaffID).SingleOrDefault();
  /* output HTML */
}
%>

So I guess what I want to do is create a new model with the following attributes:

  • ID (int) - Audit.ID
  • StaffName (string) - Staff.ID [s => s.StaffID == Staff.ID]
  • Action (string) - Audit.Action
  • Timestamp (datetime) - Audit.Timestamp

But I want to do this in the controller and pass it to the view as a ToList() so my view can be cleaner and simpler.

Any tips?

+1  A: 

You might want to consider filling both the id and name of the staff member at the time that the audit record is created, unless of course, you never do any deletes on your staff data. I typically do this because my source of people is maintained externally in our enterprise directory. Keeping the full data in the audit table means that you don't have to combine queries to get what you want and your audit data is intact even if the person doing the action leaves the company and their data is removed from the staff table. The only thing you need to worry about is name changes, which is why I keep both the id and the name so the name can be fixed up if necessary.

tvanfosson
Upvoted because it brought to my attention the audit data integrity. In theory staff should never be deleted (the app has it's own staff data store) but I like the combined approrach of ID and name.I would still like to figure out how to create my own "hybrid model" though because I think I'll need to use it for other parts of the app.
Rob Burke
A: 

Okay, so I got adventurous and tried to figure this out myself and I've got a solution but I'm not sure how correct it is!

So, firstly, I created a new class:

public class AuditEntries
{
  public int ID { get; set; }
  public string StaffName { get; set; }
  public string Action { get; set; }
  public System.DateTime Timestamp { get; set; }
}

I then refactored my ViewAuditTrail action to look like so:

[AcceptVerbs("GET")]
public ActionResult ViewAuditTrail()
{
  var Audit = (from a in db.Audits orderby a.Timestamp descending select a).ToList();

  var AuditEntry = new List<AuditEntries>();

  foreach (var e in Audit)
  {
    var Staff = (from s in db.Staffs where s.ID == e.StaffID select s).SingleOrDefault();

    AuditEntries Entry = new AuditEntries();
    Entry.ID = e.ID;
    Entry.StaffName = Staff.Forename + " " + Staff.Surname + " (" + Staff.ID.ToString() + ")";
    Entry.Action = e.Action;
    Entry.Timestamp = e.Timestamp;

    AuditEntry.Add(Entry);
  }

  return View(AuditEntry.ToList());
}

And now my ViewAuditTrail view is just a strongly-typed view bound to the AuditEntries class using the default MVC list view type.

It seems to work fine but I'm sure it can be improved upon - does anyone have any suggestions?

Rob Burke