Ayende @ Rahien

It's a girl

NHibernate Validator

Validation is one of those things that goes hand in hand with data access. I guess it is not much of surprise that one of the contrib projects for NHibernate is extensive validation support.

True, there are about as many validation frameworks as there are ToDo applications, but NHibernate Validator bring something special to the table, it brings tight integration with NHibernate itself and:

“…multi-layered data validation, where constraints are expressed in a single place and checked in various different layers of the application.”

I am sorry, I just love this quote. :-)

Anyway, let me jump right it and show you what I mean by that.

We can initialize the validation framework using several ways, but probably the easier would be:

var configuration = new Configuration()
	.Configure("hibernate.cfg.xml");

var engine = new ValidatorEngine();
engine.Configure(new NHVConfigurationBase());

ValidatorInitializer.Initialize(configuration, engine);

And now, all we need to do is set the validation attributes on our the entities, and we are done:

[NotNullNotEmpty]
[Length(25)]
public virtual string Title

At this point, several very interesting things are going to happen. First, if we ask NHibernate to generate the schema for us we are going to get the following:

Before using NHV After using NHV
create table Blogs (
  Id INT IDENTITY NOT NULL,
   Title NVARCHAR(255) null,
   Subtitle NVARCHAR(255) null,
   AllowsComments BIT null,
   CreatedAt DATETIME null,
   primary key (Id)
)
create table Blogs (
   Id INT IDENTITY NOT NULL,
   Title NVARCHAR(25) not null,
   Subtitle NVARCHAR(255) null,
   AllowsComments BIT null,
   CreatedAt DATETIME null,
   primary key (Id)
)

Note the title column, where before we used the default values (null and 255) we are now using the values defined in the validation scheme. That is what we mean when we say that we can get pretty multi layered data validation.

That is not the end of it, however, NHibernate Validator is hooking up into the NHibernate engine, and if we tried to save the following, we will get a validation exception:

s.Save(new Blog
{
	Title = new string('*',255),
});

And, obviously, we support a way to extract all the validation errors from the entity:

var invalidValues = engine.Validate(blog);
foreach (var invalidValue in invalidValues)
{
	Console.WriteLine(
        "{0}: {1}",
		invalidValue.PropertyName, 
		invalidValue.Message);
}

NHibernate Validator also support all the other things that you would expect from validation frameworks, the ability to create your own constraints (including the ability to embed them in the database schema!), i18n, XML only configuration, if you want to keep your entities clear of attributes, etc.

This has been truly just a tidbit, to whet your appetite.

You can learn more about NH Validator here.

Comments

Peter Morris
05/01/2009 09:51 AM by
Peter Morris

A nice start :-)

How would you add validation which cannot be expressed as a .NET attribute. For example an invariant which is based on an object's state.

"Signature required if the order.Status == OrderStatus.Approved"

sarong
05/01/2009 11:44 AM by
sarong

for the last project i evaluated it, but compared to castle validator its harder to extend, cause di doesn't work nice. what are your thoughts when comparing it with castle validator?

Bryan
05/01/2009 02:41 PM by
Bryan

One validation message needs the ability to invalidate multiple property names.

Example: A must be greater than B

It's one rule. It invalidates both A and B, but it's still only one rule and should ultimately display only a single error message.

I see this again and again in every validation framework and it drives me mad.

Secondly, is this another direct port from Java? I see references like "beanName" all over the source code. I thought we'd finally moved beyond this in the .NET world and were able to stand on our own?

Merritt
05/01/2009 02:53 PM by
Merritt

About 6 months ago, I invested several days looking into this framework and was very impressed.

Since I am a bit rusty on the details, I was hoping you could remind how one would use this framework to do validation based on property comparisons. For instance, say property A is only valid in a certain range and that range depends on the value of property B. Typically I have done such validation with declarative/attribute based validation frameworks within the body of a function, and somehow hooking that function into the validation process.

This question is in the same vain as Peter Morris'

Ayende Rahien
05/01/2009 03:12 PM by
Ayende Rahien

Peter,

Then you create a custom validator.

Ayende Rahien
05/01/2009 03:14 PM by
Ayende Rahien

Sarong,

I am not going to get into that. The main benefit of NHV is that it ties strongly into NH.

Ayende Rahien
05/01/2009 03:16 PM by
Ayende Rahien

Bryan,

I am not going to touch on that. Validation framework design is not something that I did.

I can comment on that it seems workable to invalidate one of them or to create two error messages, and that adding that would significantly complicate the design of most other scenarios.

And yes, this is a port of a Java project, there is no need to reinvent the wheel if it is already there and moving.

Peter Morris
05/01/2009 03:46 PM by
Peter Morris

I wouldn't want to write a custom class for something like A < B. I presume there is some kind of interface the class can implement to return broken constraints or something?

I'll ask the guy who wrote the blog entry you posted a link to :-)

eledu
05/01/2009 06:42 PM by
eledu

How this relate to the <column element when generating schemas.

eledu
05/01/2009 06:44 PM by
eledu

oops, the column element

Ayende Rahien
05/01/2009 09:23 PM by
Ayende Rahien

If you want to know from technical perspective, NHV will intercept the schema generation and add the validation to the schema itself

Ayende Rahien
05/02/2009 05:51 AM by
Ayende Rahien

Peter,

Of the top of my head, I don't think that you can implement an interface, mostly because it hurt the poconess of the class

Peter Morris
05/02/2009 07:13 AM by
Peter Morris

Adding an interface to a class to return a list of errors is still POCO in my opinion. NH has call back interface options for classes doesn't it? That isn't considered breaking the POCOness, or is it?

I like the look of the validator, but without the ability to have the class itself define more complicated invariants you'll end up writing a class per rule which can only be used on a specific entity type. In addition to that you sometimes need to access private state in order to validate.

I posted a comment on that blog you linked to but it hasn't been approved yet, we'll see if it does or not :-)

Ayende Rahien
05/02/2009 10:07 AM by
Ayende Rahien

Peter,

It creates a dependency between the class and the framework, that breaks POCO

And while NH has such interfaces, they are considered deprecated, and their use is frowned upon.

Peter Morris
05/02/2009 10:34 AM by
Peter Morris

Hi Ayende

Oh I understand the misunderstanding between us now :-) Maybe it would be better if I had written

"I presume there is some kind of interface SOME VALIDATION class can implement to return broken constraints or something?"

By this I mean that instead of writing a .NET attribute class which performs a single validation, for the complex rules I would write something like

public class Validator <person
{

}

or

public class PersonValidator : IValidator <person
{

}

Where all validation rules may be added? The big problem with validation though is when a rule depends upon private state.

private string password;

public string Password

{

set { password = value; }

}

I presume the validator attribute may also be applied to a private member?

Cheers :-)

Pete

Colin Jack
05/06/2009 09:31 AM by
Colin Jack

"Of the top of my head, I don't think that you can implement an interface, mostly because it hurt the poconess of the class"

I see what you are saying, but I consider a lot of validation to be a domain concern, so I want the option of having an object controlling many aspects of its own validation (its won invariants in particular).

Comments have been closed on this topic.