Try fast search NHibernate

29 October 2009

NHibernate.Validator & NHibernate

The validation is defined as a classic cross cutting concern… well… if we are talking about that we need to validate something everywhere I can agree with that definition, but if we are talking about the validation of domain entities I don’t agree.

The validation of a domain-entity shouldn’t happen in the persistence-layer nor in the presentation-layer and even less in the persistence itself.

Validate something in the DB (persistence) is too late and you will have some unneeded round-trips, by the way, in some very special cases is acceptable and even inevitable (read it as optimistic-lock for example).

Validate in the persistent-layer can be useful if you want a “short-cut” where put the validation (for example if you modify an entity instance, somewhere, and you don't exactly know where put the validation of the new state).

Validate in the UI, well… there you can validate only what you are showing.

The natural place for the entities-validation is the service-layer (service in DDD meaning).

If I think so, why I like NHibernate.Validator so much ?

The matter is that, in the service-layer, I’m needing to validate entities-instances provided by NHibernate and I need a validation system that know how NHibernate work with entities (perhaps, soon, somebody will realize it for EF4).

warnIf you are using something else, than NHV, to validate complex-entities-graph (with valid associations, valid collections and so on), be careful and have a look to what is happening with SQL-Queries (activating log4Net for the SQL, or testing NH-Statistics, or using NHProf, or whatever).

That said I can begin explaining some integration points leaving you the choice of its usage.

The “integrator”

The class you must use to perform the integration is NHibernate.Validator.Cfg.ValidatorInitializer.

In the ValidatorInitializer there are only two extension-methods and before write this post I wrote the documentation of both methods; now you can read it there.

A full integration may look like:

var nhvConfiguration = new FluentConfiguration();
nhvConfiguration
.SetDefaultValidatorMode(ValidatorMode.UseExternal)
.Register(Assembly.Load("Dll.Where.ValidationDefAre")
.ValidationDefinitions())
.IntegrateWithNHibernate
.ApplyingDDLConstraints()
.And
.RegisteringListeners();

var nhibernateConfig = new Configuration().Configure();

validatorEngine = new ValidatorEngine();
validatorEngine.Configure(nhvConfiguration);

nhibernateConfig.Initialize(validatorEngine);

About the ValidatorEngine and the Shared-Engine-Provider you can read in: Diving in NHibernate.Validator.

Events integration

The integration of events is basically the registration of a IPreInsertEventListener and a IPreUpdateEventListener. If you, or the NHibernate’s auto-flush, are going to save or update an invalid instance you will receive an InvalidStateException (there is happening something else, but don’t worry).

DDL integration

The DDL integration is more DBA oriented than everything else… yes DBA oriented… even to make happy the DBA in yourself (I mean some old-school DBA).

In practice, having something like this:

public class Entity
{
public int Value { get; set; }
public string Description { get; set; }
}

public class EntityValidation : ValidationDef<Entity>
{
public EntityValidation()
{
Define(e => e.Value).IncludedBetween(10, 99);
Define(e => e.Description).NotNullableAndNotEmpty().And.MaxLength(50);
}
}

with a poor persistence mapping like this

<class name="Entity">
<
id type="int"/>
<
property name="Value"/>
<
property name="Description"/>
</
class>

if you will create the schema, using NHibernate’s SchemaExport, the script will be:

create table Entity (
id INT not null,
Value INT null check( Value>=10 and Value<=99) ,
Description NVARCHAR(50) not null,
primary key (id)
)

as you can see you have a perfect tuning, like in a concert, with the DataBase, even for the CHECK-CONSTRAINT of the property Value, and, if you want, you can even create some special Trigger (your old-school DBA will be euphoric with that).

What is wrong there ?

First of all, now you have transformed a very nice and flexible software validation in something written in the stone (now somebody should maintain the constraints, even in the DB, when you will need to change the range of allowed values).

Second, and perhaps even more catastrophic… in the past week I saw a NHibernate’s user euphoric because he found a way to integrate DataAnnotations, with NHibernate, through Fluent-NHibernate; his example was using the RequiredAttribute (NotNullable in NHV)… very cool!!! no ? well… now try to apply it in a graph mapped with table-per-class-hierarchy, where some subclass have a not-nullable property, and let me know which will be the result (only for this reason we should have a SoftNotNullableAttribute).

The matter is that, for the same reason you are not using stored-procedures to do everything, you shouldn’t integrate your nice software validation with the underling DDL of your RDBMS.


The Fashion

The fashion/elegant part, of the integration, is that you can start defining your domain model with POCOs then externally map the persistence, then externally map the validation integrated with persistence, and, as a kind of magic, your POCOs will checked before persist anything; all without any kind of invasion in your existing code.

but it’s only a kind of magic, I’m not so sure that it’s so beautiful.

6 comments:

  1. Hi Fabio!

    i'm currently using castle val. cause some time ago it looked more extensible and DI works nicer than with nhv. time goes by and i'm thinking hard of switching to nhv, so i have the following questions:

    you advice to pay attention to look at the db queries when validating a object graph with somenthing else than nhv. does nhv handle fetching, and if how?

    you write about required with table-per-class-hierarchy. does this work with nhv?

    is it nice/possible to validate objects with nhv which are not known/persisted with nh, or do i have another framework for these?

    how are unique properties handled spanning more than one property?

    hopefully i didn't missed the right moment to let you know ;)

    thx

    ReplyDelete
  2. _ Yes (how is too long to explain but think about that NHV know NH)
    _ Sure if you are not using DDL integration or a custom NotNullable (Attribute or via satisfier)
    _ Yes, with NHV you can validate anything you want.
    _ coming soo (tomorrow on this channel)

    ReplyDelete
  3. Somebody have asked about uniquess validation.
    Look at comments here

    ReplyDelete
  4. Fabio, I have been doing some digging into NH Validator and one things I can't seem to find any information on is how to implement complex entity level validation. For example, what if certain combination of property values are not valid. How does one implement this? A common example is an address where we want to apply different regex validations to the postal code depending on the country code or we want to validate the state code against a known list if the country is US, etc.

    Can this be done?

    ReplyDelete
  5. Prehaps you are looking for
    http://fabiomaulo.blogspot.com/2010/01/nhibernatevalidator-changing-validation.html

    ReplyDelete