Automatically username stamping entities as they’re saved

The application I am currently working on has a requirement to audit which application user last created or updated database records. All tables in the database are required to have an nvarchar column UserName.

I didn’t want this concern to leak into my application. After some investigation I discovered that ObjectContext has the SavingChanges event that would be ideal for my purposes.

So the creation of my ObjectContext becomes

var entities = new MyEntities();
entities.SavingChanges += SetUserNameEvent;

I originally thought that SetUserNameEvent would have to use reflection to obtain and set the UserName property. However I found a way to use T4 to generate code resulting in all entities with the UserName property implementing a common interface (IUserNameStamped). I’ve written a blog post talking about about the T4 code.

So with all my entities implementing this common interface, SetUserNameEvent is then

/// <summary>
/// Sets the user name of all added and modified 
/// entities to the username provided by
/// the <see cref="UserNameProvider"/>. 
/// </summary>
private void SetUserNameEvent(object sender, EventArgs e)
{
    Contract.Requires<ArgumentException>(
        sender is ObjectContext, 
        "sender is not an instance of ObjectContext");
    var objectContext = (ObjectContext)sender;
    foreach (ObjectStateEntry entry in 
        objectContext.ObjectStateManager.GetObjectStateEntries(
            EntityState.Added | EntityState.Modified))
    {
        var stamped = entry.Entity as IUserNameStamped;
        Contract.Assert(stamped != null, 
            "Expected all entities implement IUserNameStamped");
        stamped.UserName = UserNameProvider.UserName;
    }
}

So here, we get all added and modified entries from the ObjectStateManager, and use these to obtain the entities and set their UserName. UserNameProvider is an abstraction used as I have several applications utilising my object context, each with a different way to obtain the current application user. Note that my code is using Code Contracts.

One complication I’ve found is with child entities. Sometimes, I’ve found I have to add the child entity both to its parent object and to the object context, but sometimes it’s enough to simply add the child entity to it’s parent object. That is:

var entities = ObjectContextFactory.GetObjectContext();
var childEntity = new ChildEntity();
entities.ParentEntities.First().ChildEntities.Add(childEntity);
// entities.ChildEntities.AddObject(childEntity);
entities.SaveChanges()
// Sometimes UserName will not get set without the commented line above, 
// resulting in a NOT NULL constraint violation

I’ve found no rhyme or reason as to why the addition to the ObjectContext is only sometimes required, I’d love hints as to why this is.

Note I’m actually using the unit of work pattern for my application, and I use a unit of work factory rather than an object context factory, but that’s irrelevant to the use of the SavingChanges event in this fashion.