Skip to content

David Turvey's Blog

All About Development

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

If you need your all your LINQ to SQL entities to inherit from a base class or to implement an interface there is an easy way to do it. The first way that comes to mind for most people is to create a partial class for the entities and specify the inheritance (or interface implementation) in the partial class. While this will work it is a mission as it means you need a matching partial class for every LINQ to SQL entity in your DBML, and there is no guarantee that any new entities that are added by other team members will inherit from the base class or implement the interface.

There is a far simpler way to ensure that all LINQ to SQL entities inherit from a base class or implement an interface. Unfortunately there isn’t a way to do it from the LINQ to SQL designer, you need to open up the DBML file in a text editor. On the Database node simply add the attribute EntityBase along with the name of the base class or interface.

<Database Name="Northwind"
	Class="MyDataContext"
	xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007"
	EntityBase="MyEntityBase">
</Database>

If the base class or interface is not in the same namespace as your LINQ to SQL entities then you will need to specify the full qualified name of the base class or interface.

It looks like Google Street View is finally coming to South Africa, my dad spotted this Google car driving past his house in Midrand the other day – driving around a gated community I might add :)

Google Street View Car in Midrand, Gauteng, South Africa

Google Street View Car in Midrand, Gauteng, South Africa

My dad managed to stop the driver and have a chat with him, apparently Cape Town and Pretoria are done, and there are 4 teams working the Johannesburg area. No mention when it’s going live but I guess the driver wouldn’t know that.

Google Maps for South Africa has gone live though; check it out at http://maps.google.co.za/

When you want to convert a string to an integer the two most popular approaches are to use int.Parse() or System.Convert.ToInt32(), both of which are static functions. (I’m not going to include int.TryParse(), System.Convert.ChangeType(), etc. in this discussion). Personally I always use int.Parse(), why? Well I don’t actually have a good reason; I’ve always just thought it looks cleaner.

So why would you choose to use one over the other? Well I guess it really depends on what you need; from my short investigation I was able to spot the following differences:

  • Passing a null string into int.Parse() will throw an ArgumentNullException. Passing a null string into System.Convert.ToInt32() will return 0 (i.e. the default for int).
  • int.Parse() has an overload where you can pass in the NumberStyles flags enum to specify how the string should be handled. System.Convert.ToInt32() does not have this overload.
  • System.Convert.ToInt32() has an overload where you can specify the number base of the string, i.e. base 2, 8, 10, or 16.

Available overloads on int:

public static int Parse(string s)
public static int Parse(string s, NumberStyles style)
public static int Parse(string s, IFormatProvider provider)
public static int Parse(string s, NumberStyles style, IFormatProvider provider)

Available overloads on System.Convert (for the input type string):

public static int ToInt32(string value)
public static int ToInt32(string value, IFormatProvider provider)
public static int ToInt32(string value, int fromBase)

Some other points for you:

  • If you don’t provide the IFormatProvider both int.Parse() and Sytem.Convert.ToInt32() will retrieve the format off the CurrentCulture.
  • If you do not specify the NumberStyles for int.Parse() it will simply use NumberStyles.Integer.
  • System.Convert.ToInt32(string) and System.Convert.ToInt32(string, IFormatProvider) both call int.Parse() to do the conversion, where as System.Convert.ToInt32(string, int) calls ParseNumber.StringToInt(). This is a static internal class so you will need to use Red Gate’s .NET Reflector if you want to see it. Something interesting about this call is that it makes an internal call to a method in the CLR to do the conversion.

Looking at the corresponding methods for conversion on the other types it appears they seem to work in a similar way, with the exception that System.Convert.ToDouble() and System.Convert.ToDecimal() do not provide an overload to specify the number base.

For those that are interested here are some of the RSS feeds for the blogs that I follow:

  • Channel 9
    Channel 9 is the MSDN video website for all things dev related.
  • dotnet.org.za
    Not a create site and most of the blog just rehash posts from other blogs but once in a while it has something useful.
  • Eric Lippert’s Fabulous Adventures In Coding
    This is a blog I love, this guy works on the .Net Framework and posts some awesome goodies. If you want to be a good dev you should understand the framework’s internals and this blog will help with that.
  • InfoQ (go to the site to create a custom feed)
    A lot of the stuff on here is high level, you won’t find many coding examples etc. But it has some great posts and the range of articles is very broad.
  • Microsoft StyleCop
    This is just so that I know when StyleCop is updated.
  • Mike Taulty’s Blog
    This blog pretty much focuses on SilverLight and Mike Taulty has a number of webcasts on SilverLight if you need to get going with it.
  • Microsoft Architecture Center
    Just as the name says, Architecture related articles, some interesting, some boring.
  • Mythical Man Moth
    A blog I discovered by another South African, I haven’t gone through all his posts yet but there are some interesting ones.
  • rohland.co.za
    Another South African blog I discovered just a few days ago, I’m still going through the posts.

Then some blogs by various developers, I’m not going to comment on them, I’m sure you probably know most of these blogs already:

If you’re frustrated and need a good laugh plug into this feed ;)
ICanHasCheezburger