Try fast search NHibernate

15 February 2009

NHibernate.Validator: fluent-interface configuration

As announced in the previous post NHibernate.Validator (NHV for friends) has its own embedded configuration based on fluent-interface (Loquacious for friends). This new feature will be general-available with the next version NHV1.2.0.

The NHV configuration

As test and because the new configuration is “Loquacious” enough I’m going to expose some examples without explication.

Example 1:

var configure = new FluentConfiguration();
configure.Register(
Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.Namespace.Equals("Company.Product.YourNamespace"))
.ValidationDefinitions())
.SetDefaultValidatorMode(ValidatorMode.UseExternal);

ve = new ValidatorEngine();
ve.Configure(configure);

Example 2:

var configure = new FluentConfiguration();
configure.Register(
Assembly.Load("Company.Product")
.ValidationDefinitions()
.Where(t => t.Namespace.Equals("Company.Product.YourNamespace"))
)
.SetDefaultValidatorMode(ValidatorMode.UseExternal)
.IntegrateWithNHibernate.ApplyingDDLConstraints().And.RegisteringListeners();

ve = new ValidatorEngine();
ve.Configure(configure);

The only thing you can’t configure, using FluentConfiguration, is the SharedEngineProvider because it is configurable only trough application config (by the way, from what I saw on the NET, an explication about what is the SharedEngineProvider is needed).

For the configuration, I have add two extensions methods, both named ValidationDefinitions(), to Assembly and to IEnumerable<System.Type>.

The configuration of class validation

Example v1:

public AddressDef()
{
Define(x => x.Country)
.MaxLength(20).And
.NotNullable();
Define(x => x.floor)
.IncludedBetween(-2, 50).WithMessage("{floor.out.of.range}");
Define(x => x.Id)
.IncludedBetween(1, 2000);
Define(x => x.Line1)
.NotNullable();
Define(x => x.State)
.NotNullable().And
.MaxLength(3);
Define(x => x.Zip)
.NotNullable().And
.MaxLength(5).WithMessage("{long}").And
.MatchWith("[0-9]+");
Define(x => x.InternalValid)
.IsTrue();
}

What happen at design-time ? Some images are more clear than 100 words…

DateTimePropVSIntegerPropVS  DecimalPropVS StrPropVSEnumerablePropVSEntityRelationPropVS  

The first advantage of fluent-interface-configuration appear clear: a very little example is that you can’t define an integer property as not-nullable.

For instance validators here is the example using Attributes and its equivalent using fluent-configuration:

Example v2:
[AssertAnimal]
public class Suricato
{
}

public class SuricatoDef:ValidationDef<Suricato>
{
public SuricatoDef()
{
ValidateInstance.Using(new AssertAnimalAttribute());
}
}

Extending constraints configuration

Who know NHV know that we have some country-specific validators. Country-specific-validator is a clear example about how extend the framework.

The follow is the implementation of NHibernate.Validator.Specific.It (validators available for Italy):

public static class ItLoquaciousExtensions
{
public static IRuleArgsOptions IsCodiceFiscale(this IStringConstraints definition)
{
return ((IConstraints)definition).AddWithFinalRuleArgOptions(new CodiceFiscaleAttribute());
}

public static IRuleArgsOptions IsPartitaIva(this IStringConstraints definition)
{
return ((IConstraints)definition).AddWithFinalRuleArgOptions(new PartitaIvaAttribute());
}

public static IRuleArgsOptions IsPartitaIva(this IIntegerConstraints definition)
{
return ((IConstraints)definition).AddWithFinalRuleArgOptions(new PartitaIvaAttribute());
}
}

And obviously, at design-time, it appear like this:

It_IntegerPropVS

Conclusions

Sometimes NHV is not so well know by NHibernate users (NHV has 5% of NH downloads). If you are using some other validation framework, in applications where you are using NHibernate, you should check if the validator are initializing collections and relations (proxy)… perhaps we should write something else about how NHV work together with NHibernate.



kick it on DotNetKicks.com

4 comments:

  1. Great job Fabio! I really like the final syntax.

    ReplyDelete
  2. Great job !!!
    But I have one question ... :(
    In our project we are using NHV. At the moment I have an issue because in different contexts I've to validate a entity accordingly. Fluent validation I thought is the solution also but it isn't so. Is it possible to have something similar myEntityInUpdateContext.GetValidationResultForRule(new ThisIsNonDefaultRegisteredValiRuleForThisEntity())
    I would appreciate any sugestions

    ReplyDelete
  3. You can do it creating a new VE. BTW create a JIRA ticket with your request; the feature is easy to implements.

    ReplyDelete
  4. I apologise if this is a newbie question, but what is the recommended way to set the maximum field length. Which comes first; the database of the configuration?

    The way I see it, if you start with the database, then the configuration(mapping) should automatically know the maximum field length (for strings at least).

    If you start with the configuration(mapping), I assume you can create the database creation script. So how do you handle a change in schema if there is data in your database?

    Update the mapping and do some sort of export to genearte the alter script?

    Is there a way to have .NET automatically set the field length on single line edits based on a nhibernate field length?

    Thanks.
    Bill.

    ReplyDelete