As you know LINQ to SQL entities have OnCreated, OnLoaded, and OnValidate “events”; which are actually just partial methods which you implement in your matching partial custom classes for your LINQ to SQL entities. Two “events” that are missing that can be quite useful are OnSaving and OnSaved which would fire before writing to the database and after writing to the database.
Adding this functionality is fairly easy; first add a base class to your LINQ to SQL entities as described in my post Adding a Base Class (or Interface) to All LINQ to SQL Entities and add the virtual methods OnSaving and OnSaved as below.
public abstract class EntityBase
{
internal virtual void OnSaving(ChangeAction changeAction) { }
internal virtual void OnSaved() { }
}
Then for any LINQ to SQL entities that you wish to have hooked up to these “events” implement the partial class and override the methods, for example you could use the OnSaving “event” to set your audit data:
public partial class Customer
{
internal override void OnSaving(ChangeAction changeAction)
{
base.OnSaving(changeAction);
switch (changeAction)
{
case ChangeAction.Insert:
InsertedDate = DateTime.Now;
break;
case ChangeAction.Update:
UpdatedDate = DateTime.Now;
break;
default:
break;
}
}
}
Create a class called ChangeEntity and add the properties ChangeAction and Entity to the class, this class will be used later so that we know what action is happening to each entity.
internal class ChangeEntity
{
public ChangeAction ChangeAction { get; set; }
public EntityBase Entity { get; set; }
}
Now what we need to do is override the SubmitChanges method on the data context, the parameterless SubmitChanges method cannot be overridden as it is not virtual so we override the method SubmitChanges(ConflictMode failureMode); which the parameterless method calls.
We will then create a list of all the entities that have been modified (i.e. inserted, updated, or deleted) using the ChangeSet object that is returned by the GetChangeSet() method – the returned object has a seperate list for Deletes, Inserts, and Updates which we will join together into a single list.
Then we build up a list of ChangeEntity objects which will contain a reference to each entity to be changed and an enum of type ChangeAction stating the action to take place for each entity; namely Insert, Update, or Delete.
Then we enumerate through the list of ChangeEntity and call the method OnSaving on each entity.
Then we call SubmitChanges on the base class, and finally we enumerate throught the list of ChangeEntity once again and call the method OnSaved on each entity.
Below is the required code, it is more verbose that I would usually write but the original code didn’t display nicely
public partial class DataClassesDataContext
{
public override void SubmitChanges(ConflictMode failureMode)
{
// Get the entities that are to be inserted / updated / deleted
ChangeSet changeSet = GetChangeSet();
// Get a single list of all the entities in the change set
IEnumerable<object> changeSetEntities = changeSet.Deletes;
changeSetEntities = changeSetEntities.Union(changeSet.Inserts);
changeSetEntities = changeSetEntities.Union(changeSet.Updates);
// Get a single list of all the enitities that inherit from EntityBase
IEnumerable<ChangeEntity> entities =
from entity in changeSetEntities.Cast<EntityBase>()
select new ChangeEntity()
{
ChangeAction =
changeSet.Deletes.Contains(entity) ? ChangeAction.Delete
: changeSet.Inserts.Contains(entity) ? ChangeAction.Insert
: changeSet.Updates.Contains(entity) ? ChangeAction.Update
: ChangeAction.None,
Entity = entity as EntityBase
};
// "Raise" the OnSaving event for the entities
foreach (ChangeEntity entity in entities)
{
entity.Entity.OnSaving(entity.ChangeAction);
}
// Save the changes
base.SubmitChanges(failureMode);
// "Raise" the OnSaved event for the entities
foreach (ChangeEntity entity in entities)
{
entity.Entity.OnSaved();
}
}
}


