views:

167

answers:

4

I am attempting to use the Microsoft enterprise Validation methods to perform validation in my entities. In my base class I have the following method:

public class BaseEntity
{
  public bool IsValid()
  {
     return Validate().IsValid;
  }

  public ValidationResults Validate()
  {
     return Validation.Validate<this.GetType()>(this);
}

The problem with this is that even when a subclass of BaseEntity calls IsValid, this.GetType() always returns BaseEntity, not the Subclass's type. I don't want to have to rewrite this code for every entity, as that seems very un-OO like. Is there any other way to do this?

I did have the idea to have a protected variable protected Type _validationType, and in every entity set it to that entity's .GetType value, but it seems like there has to be a better way to do this.

Update
Nevermind apparently. this.GetType() seems to be working as I was hoping. Not sure why it wasn't before.

I also changed my Validate() method to use the following code:

 return ValidationFactory.CreateValidator(this.GetType()).Validate(this);
+2  A: 

Its very un-OO like for the base class to know anything about the subclasses. This works the way it should work.

If you want to know something about the subclasses, then you need to override this method.

Gabriel McAdams
A: 

You can make IsValid() and Validate() a virtual method to provide some custom definitions in sub classes.

Amby
A: 

Moving the type logic out of BaseEntity is cleaner.

public class BaseEntity
{
    public bool IsValid()
    {
        return Validate().IsValid;
    }

    public ValidationResults Validate()
    {
        return Validation.Validate(this);
    }
}
public class Validation
{
    public static ValidatorResults Validator<T>( T entity )
        where T : BaseEntity
    {
        return ValidationFactory.CreateValidator(entity.GetType()).Validate(entity);
    }
}
Lachlan Roche
+2  A: 

When you use an O/RM mapper such as LINQ to SQL, NHibernate or LINQ to Entities (ADO.NET Entity Framework) I'd go with another approach of validating. I'd keep the entities completely clean of validation (so no BaseEntity.Validate() in there. You can move this validation logic to the ObjectContext (EF) / DataContext (L2S) / Session (NH) and trigger validation during a database submit. Look at the example below for LINQ to SQL:

public partial class NorthwindDataContext
{
    public override void SubmitChanges(ConflictMode failureMode)
    {
        var invalidResults = (
            from entity in this.GetChangedEntities()
            let type = entity.GetType()
            let validator = ValidationFactory.CreateValidator(type)
            let results = validator.Validate(entity)
            where !results.IsValid
            from result in results
            select result).ToArray();            

        if (invalidResults.Length > 0)
        {
            // You should define this exception type
            throw new ValidationException(invalidResults);
        }

        base.SubmitChanges(failureMode);
    }

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

In the case your entities are invalid, an ValidationException will be thrown. You can catch that specific exception and iterate the InvalidResults property that you'd define on it.

When you need more information, I advise you to read this article. It also describes how to do this with Entity Framework.

Good luck.

Steven
I like this actually. I originally did not like putting validation in the entity itself, but the only other solution I could figure out or find was to create a very very thin layer in between my nhibernate classes and my entities (which I wasn't happy with). This actually solves a lot of issues, especially when used against the nhibernate validator stuff which I found (due to this post). Thanks!
KallDrexx
@KallDrexx: I'm glad you like it. I never tested how this works on NHibernate, so any examples of this are welcome.
Steven
I've seen some examples, mostly using the nhibernate validation library (and using xval as an abstraction layer). I haven't looked hard at the examples yet as first I am going to look at implementing xval into my application, and then from there I will look at connecting nhibernate to it (everything I see is just as simple as telling the validation library to hook it's handlers into the ISession).
KallDrexx