Validation Method Timing in LINQ To SQL - Hilton Giesenow's Jumbled Mind

Hilton Giesenow's Jumbled Mind

the madness that is...

News

This is my little spot in cyberspace where you will find a collection of random (but mostly software-related) thoughts and ideas that are frightening in their shining brilliance (or something like that ;->).
 
Please enjoy your stay and feel free to Contact Me.
 
Microsoft MVP

.Net Links

BlogRoll

Misc. Links

Syndication

Validation Method Timing in LINQ To SQL

The LINQ To SQL designer-generated classes contain 3 different ways to implement validation based on property values. Two of these are internal, in the form of partial methods, and one is external in the form events on the domain classes themselves. However, the timing around these differs slightly, so I'm going to examine them according to the timing.

To look into these approaches, I'm using the Customers table from Northwind. I've got it on my LINQ To SQL designer, and I've implemented the following additional  partial class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public partial class Customer
    {

        partial void OnCityChanging(string value)
        {
            if (value == "Cape Town")
                throw new Exception("Not in my town!");
        }

        partial void OnCityChanged()
        {
            if (this.City == "Johannesburg")
                throw new Exception("What are you doing up there?!");
        }

    }
}

In this class, you can see that I'm validating the "city" property both before and after it is set. What is important is that this validation code will fire directly during the property setter on the domain class. For instance, an exception will be thrown for both of the following two cases:

Customer c = new Customer();
c.City = "Cape Town";

and

Customer c = new Customer();
c.City = "Johannesburg";

and in fact the validation is roughly equivalent in terms of timing because both of these methods are called during the property setter, as the following code snippet from the designer-generated code show:

[Column(Storage="_City", DbType="NVarChar(15)")]
public string City
{
    get
    {
        return this._City;
    }
    set
    {
        if ((this._City != value))
        {
            this.OnCityChanging(value);
            this.SendPropertyChanging();
            this._City = value;
            this.SendPropertyChanged("City");
            this.OnCityChanged();
        }
    }
}

Of course, this also implies that validation outside of the Customer class structure (i.e. using the PropertyChanging or PropertyChanged events, fired via the SendPropertyChanging and SendPropertyChanged methods, respectively) will occur at the same. As a point of common sense, I would recommend doing the validation in the "changing" methods because then the value has not yet in fact been set and the change can be effectively "rolled back".

In contrast to the above approach, it is possible to subsume all of your validation logic into one place and implementing the OnValidate partial method, as follows:

partial void OnValidate(System.Data.Linq.ChangeAction action)
{
    if (this.ContactName == "Hilton Giesenow")
        throw new Exception("He's too young for Northwind!!");
}

But this method has two important points of interest. First off, it allows you to potentially control the type of change that is occurring in the database (via the ChangeAction enumeration, which has values of None, Insert, Update and Delete). In addition, the timing is quite different on this method - it only fires as part of the final SubmitChanges method call on the datacontext - i.e. when the database call is about to be made. If you are creating a new instance, for instance for an Insert, and setting the properties just before the call to SubmitChanges, the difference in timing between these two approaches is basically academic. However, if you are creating a new Customer and setting properties as part of a series of UI operations for instance, and only planning to make the SubmitChanges database call at a later stage, this difference is of some importance.

I would suggest that the safest approach is to combine the two by moving the actual validation logic out into a separate method (to keep it DRY, of course) and calling it from both places, like so:

partial void OnValidate(System.Data.Linq.ChangeAction action)
{
    ValidateCity(this.City);
}

partial void OnCityChanging(string value)
{
    ValidateCity(value); 
}

partial void OnCityChanged()
{
    ValidateCity(this.City);
}

protected void ValidateCity(string value)
{
    if (value == "Cape Town")
        throw new Exception("Not in my town!");
    else if (value == "Johannesburg")
        throw new Exception("What are you doing up there?!");
}

(I know I've removed the ContactName validation and replaced it with the ValidateCity call in the OnValidate - I was trying to illustrate the consolidated approach).

This approach doesn't cover the external clients, but this sort of validation should be internal to the class anyway.

For an different angle on this stuff  with some great additional areas of coverage, check out Simple Validation with LINQ to SQL Classes by Beth Massi.

Posted: Aug 07 2008, 09:47 PM by hiltong | with 2 comment(s)
Filed under: ,

Comments

Craig Nicholson said:

Surely then the OnChanged implementation is redundant as you have implemented the OnChanging method? Why have both still, unless I missed something. And if you implemented OnChanging, which would be my preferred choice, wouldn't OnValidate then be redundant and just extra overhead?

I can also see when implementing OnValidate only would be a logical choice as the validation logic could utilise more fields and order of setting the properties would be irrelevant.

# August 8, 2008 10:27 PM

hiltong said:

Yeah, you obviously wouldn't implement OnChanging and OnChanged to do the same thing - I was just illustrating some usage options. In terms of OnChanging(Changed) vs OnValidate, they likewise have different goals. However, it is also possible that properties may be set in another way (for instance via reflection or serialization), or you may want per-property vs one large onsave, so I would recommend having both approaches available, possibly even both implemented

# August 10, 2008 8:00 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: