views:

93

answers:

1

I'm trying to implement a validation framework in a base class for LINQ to SQL entities. The problem I'm having is getting the OnValidate event to fire properly.

The reason is that OnValidate is marked as partial so I can't provide a default implementation in the base class; it gets hidden by a new method declared by the LINQ to SQL class.

How can I fix it so the OnValidate event in the base class will be called automatically?

Example code follows below.

public class EntityBase
{
    public bool IsValid
    {
        get { return (GetValidationErrors().Count() == 0); }
    }

    public virtual IEnumerable<ValidationError> GetValidationErrors()
    {
        yield break;
    }

    public void OnValidate(System.Data.Linq.ChangeAction action)
    {
        //This never gets fired unless I call explicitly in the derived class.
        if (!IsValid) 
        {
            StringBuilder sb= new StringBuilder();
            sb.AppendLine("Validation errors prevent saving");
            foreach (ValidationError error in GetValidationErrors())
            {
                sb.AppendLine(String.Format("{0}: {1}", error.PropertyName, error.ErrorMessage));
            }
            throw new ApplicationException(sb.ToString());
        }
    }
}

public partial class LinqThingy: EntityBase
{
    public override IEnumerable<ValidationError> GetValidationErrors()
    {
        if (String.IsNullOrEmpty(Name)) yield return new ValidationError("Name required", "Name");
    }

    //Eww nasty, don't want to have to do this.
    partial void OnValidate(System.Data.Linq.ChangeAction action)
    {   
        base.OnValidate(action);
    }
}
+1  A: 

You can override the SubmitChanges(ConflictMode) method in your DataContext class. This will ensure that all entities get validated just before they are persisted. This way you won't have to create a custom base class for entities. Here's an example of how to extend the DataContext class:

public partial class NorthwindDataContext
{
    public override void SubmitChanges(ConflictMode failureMode)
    {
        EntityValidator.Validate(this.GetChangedEntities());
        base.SubmitChanges(failureMode);
    }

    private IEnumerable<object> GetChangedEntities()
    {
        ChangeSet changes = this.GetChangeSet();
        return changes.Inserts.Concat(changes.Updates);
    }
}

In the example above the custom validation logic goes into the Validate method in the EntityValidator class (you'll have to create it of course).

This article shows how to validate entities in with an O/RM technology such as LINQ to SQL. While it uses Enterprise Library Validation Application Block, the article might be applicable in your situation.

Steven