Try fast search NHibernate

Showing posts with label Validator. Show all posts
Showing posts with label Validator. Show all posts

29 June 2010

Alt.Net Hispano Vale!!

Bueno, que Alt.Net Hispano, con todo su aporte, Vale mucho ya lo saben.

La novedad es que el sabado pasado, para llenar un sabado sin VAN, hicimos un Alt.Net café con un poco de ejercicio de TDD al estilo Maulo (que vendría a ser como me sale a mi).

El resultado es que nació un nuevo framework de validación que se espera nos sirva para involucrar más gente al mundo OpenSource y, tal vez, para generar otros ejemplos de varias herramientas y tecnicas que el mundo Alt.Net quiere mucho.

El video del encuentro, como siempre, lo pueden ver en el wiki de las reuniones .

El sitio del nuevo framework es http://vale.codeplex.com/ y su nacimiento fue grabado en un screencast:

15 January 2010

NHibernate.Validator: Changing validation from/by aggregate

This post is more a self-remainder but it can be useful for you if your are using NHV to validate even Business-Rules.

NHV was designed more thinking about properties-constraints than Business-Rules, by the way it was evolving and it can be used even for some business-rules. In the last 6 or 5 months I have received questions about how solve some specific situations and, each time, I’m giving a different solution using a different NHV’s feature. The last time I even proposed the implementation of a new and unnecessary feature (take a look at this thread)… at least as self-reminder a post is needed.

The case

public class Customer
{
public string CompanyName { get; set; }
public string VatIdentificationNumber { get; set; }
}

public class Invoice
{
public Customer Customer { get; set; }
public decimal Amount { get; set; }
}

Rules are:

  • The customer must have a not empty CompanyName.
  • The customer may have VatIdentificationNumber and if he has one it must be a valid Italian’s Patita-IVA.
  • The invoice must have a valid Customer.
  • When a Customer is used to emit an Invoice, the Customer must have a Italian’s Patita-IVA.

As you can see the Customer class has different constraints depending on the aggregate from where it is used/associated.

The test

public class BusinessRuleDemo
{
ValidatorEngine validatorEngine;

[TestFixtureSetUp]
public void CreateValidatorEngine()
{
var configure = new FluentConfiguration();
configure.Register(new[] { typeof(CustomerValidation), typeof(InvoiceValidation) })
.SetDefaultValidatorMode(ValidatorMode.UseExternal);
validatorEngine = new ValidatorEngine();

validatorEngine.Configure(configure);
}

[Test]
public void CustomerValidWhenHaveCompanyName()
{
(new Customer {CompanyName = "ACME"}).Satisfy(c => validatorEngine.IsValid(c));
}

[Test]
public void CustomerNotValidWhenHaveInvalidVatIdentificationNumber()
{
(new Customer { CompanyName = "ACME", VatIdentificationNumber = "123"}).Satisfy(c => !validatorEngine.IsValid(c));
}

[Test]
public void CustomerValidWhenHaveValidVatIdentificationNumber()
{
(new Customer {CompanyName = "ACME", VatIdentificationNumber = "01636120634"})
.Satisfy(c => validatorEngine.IsValid(c));
}

[Test]
public void InvoiceNotValidWhenDoesNotHaveCustomer()
{
(new Invoice()).Satisfy(invoice=> !validatorEngine.IsValid(invoice));
}

[Test]
public void InvoiceNotValidWhenHaveCustomerWithoutVatIdentificationNumber()
{
(new Invoice { Customer = new Customer { CompanyName = "ACME" } })
.Satisfy(invoice => !validatorEngine.IsValid(invoice));
}

[Test]
public void InvoiceNotValidWhenHaveCustomerWithInvalidVatIdentificationNumber()
{
(new Invoice { Customer = new Customer { CompanyName = "ACME", VatIdentificationNumber = "123" } })
.Satisfy(invoice => !validatorEngine.IsValid(invoice));
}

[Test]
public void InvoiceValidWhenHaveCustomerWithValidVatIdentificationNumber()
{
(new Invoice { Customer = new Customer { CompanyName = "ACME", VatIdentificationNumber = "01636120634" } })
.Satisfy(invoice => validatorEngine.IsValid(invoice));
}
}

The solution

I’m pushing you to use the new loquacious mapping of NHibernate.Validator because the class where you are defining all constraints become the class with responsibility of validation of an entity so, in this example, I will use our dear Loquacious.

public class CustomerValidation : ValidationDef<Customer>
{
public CustomerValidation()
{
// The customer must have a not empty CompanyName
Define(e => e.CompanyName).NotNullableAndNotEmpty();

// The customer may have VatIdentificationNumber and if he has one it must be a valid Italian’s Patita-IVA.
Define(e => e.VatIdentificationNumber).IsPartitaIva();
}
}

public class InvoiceValidation : ValidationDef<Invoice>
{
public InvoiceValidation()
{
ValidateInstance.By((invoice, validationContext) =>
{
bool isValid = true;

// When a Customer is used to emit an Invoice, the Customer must have a Italian’s Patita-IVA
if (invoice.Customer != null && string.IsNullOrEmpty(invoice.Customer.VatIdentificationNumber))
{
isValid = false;
validationContext.AddInvalid<Customer, string>("To be used in an invoice the Customer should have the VatNumber",
p => p.VatIdentificationNumber);
}

return isValid;
});

// The invoice must have a valid Customer
Define(e => e.Customer).IsValid().And.NotNullable();
}
}

As you can see I’m using the ValidateInstance but this time with a “special” overload where I can change the validation-context. A validation-context is created each time we are validating an object-graph (each time we are calling a validation-method of the ValidatorEngine) and we can use it to add invalid-values to the validation; in this case I’m using it to validate the existence of the VatIdentificationNumber.

That’s all.

17 November 2009

NHibernate.Validator: Tags

At the begin of NHibernate Validator we have talked about the exigency of assign a “gravity level” to each validation (for instance Error, Warning, Information). In the last year we had requests for “validation grouping” and “different validation, for the same entity, in different contexts”.

Our answer is: validation tagging

What is a tag

In NHibernate Validator a tag has de same meaning you are giving to a tag in your blog, bookmarks, feed reader, Wave and so on. This mean that each validation-constraint may have none, one or more tags.

The type of the Tag is your choice; you can use System.Type, string, enum, int or whatever you want implements IEqualityComparer and… yes!! even altogether:

public class Error { }
public class Warning { }

public enum MyEnum
{
Error,
Warining
}

public class Entity
{
[Min(Value = 20, Tags = typeof(Error))]
[Max(Tags = new[] { typeof(Error), typeof(Warning) }, Value = 100)]
public int ValueUsingTypes { get; set; }

[Min(Value = 20, Tags = "error")]
[Max(Tags = new[] { "error", "warning" }, Value = 100)]
public int ValueUsingStrings { get; set; }

[Min(Value = 20, Tags = MyEnum.Error)]
[Max(Tags = new[] { MyEnum.Error, MyEnum.Warining }, Value = 100)]
public int ValueUsingEnums { get; set; }

[Min(20)]
[Max(100)]
public int ValueWithoutTags { get; set; }
}

If you are using the XML mapping (to configure the validation), all Tags are strings but using attributes or Loquacious you can use anything you want.

Even the follow declaration is possible:

[Min(Value = 20, Tags = new object[] {typeof(Error), 1, "warning"})]

The usage of an array of objects is a language limitation but, at the end, we can read it as a feature ;-) (have a look to the end of this link).

How validate using Tags

Tags are available in any method used, in the ValidatorEngine, to validate a property or an entity. To explain how work with Tags I prefer to show you some examples:

Example 1:
var entity = new Entity();
validatorEngine.Validate(entity);

This is the “normal” usage without tags. In this case we have four invalid values (one for each property) because without specify a tag we will use all constraints, and in this case, we are breaking all Min constraints.

Example 2:
var entity = new Entity();
validatorEngine.Validate(entity, typeof(Warning));

We have only one constraint tagged with typeof(Warning) : the property ValueUsingTypes should be less than or equal to 100. As default ValueUsingTypes=0 so, using the example2, we will have a valid entity (none invalid values).

Example 3:
var entity = new Entity {ValueUsingTypes = 101};
validatorEngine.Validate(entity, typeof (Warning));

Similar situation of the previous example but this time ValueUsingTypes is greater than 100 so we will have one invalid value.

Example 4:
var entity = new Entity();
validatorEngine.Validate(entity, typeof (Error), null);

Here I’m using two tags: typeof(Error) and the other tag is null. In this case we are selecting all constraints tagged with typeof(Error) and all constraints without tags so we will have two invalid values: ValueUsingTypes is less than 20 and ValueWithoutTags is less than 20.

In practice null is a special reserved tag used to select those constraints without a specific tag.

Example 5:
var entity = new Entity();
validatorEngine.Validate(entity, typeof(Error), MyEnum.Error, "error");

I’m using three Tags: typeof(Error), MyEnum.Error, "error". We will have three invalid values: ValueUsingTypes is less than 20 and ValueUsingStrings is less than 20 and ValueUsingEnums is less than 20.

Example 6:

To validate only those constraint without a tag the syntax is:

var entity = new Entity();
validatorEngine.Validate(entity, new object[] {null});
In this case we will have only one invalid value: ValueWithoutTags is less than 20.

Consideration

In the examples above I have used a really strange way to use Tags only to show you the freedom you having. My personal advise is to define one, two or as most three “meaning” tags. Take care with tagged and no-tagged constraints: in my opinion you should work with all tagged constraint or without tags; if you want mix tagged with no-tagged, don’t forget example-1, example-4 and example-6. If you have some constraints involving the persistence and you want run it only when all others constraints does not have invalid values, the "constraint tagging" is a good candidate to solve the issue.

The result InvalidValue with Tags

The InvalidValue class now has a new property: MatchTags. The new property will contain the intersect between the tags declared for a constraint and the tags used for a specific validation.
Example :
public static class Tags
{
public static readonly string Error = "Error";
public static readonly string Warning = "Warning";
public static readonly string Information = "Information";
}
public class Entity
{
public int ValueMinMax { get; set; }
public int ValueMin { get; set; }
}
public class EntityValidator : ValidationDef<Entity>
{
public EntityValidator()
{
Define(x => x.ValueMinMax)
.Satisfy(v => v >= 20).WithTags(Tags.Error)
.And
.Satisfy(v => v <= 100).WithTags(Tags.Error, Tags.Warning);

Define(x => x.ValueMin)
.GreaterThanOrEqualTo(20).WithTags(Tags.Warning, Tags.Information);
}
}

running a validation as

var entity = new Entity { ValueMinMax = 101 };
validatorEngine.Validate(entity, Tags.Information, Tags.Warning);

For the InvalidValue related to ValueMinMax property the MatchTags is “Warning”

For the InvalidValue related to ValueMin property, the MatchTags is [“Warning”, “Information”]

15 November 2009

Refactorizing tests

I had read, in some place on the cloud, that SharpTestsEx make the test more verbose even if it is more readable.

In NHibernate.Validator (NHV) we are using #TestsEx. After implements some new features I’m improving some stuff where I’m needing a little breaking change.

This is an existing test using classic NUnit syntax:

[Test]
public void CreditCard()
{
CreditCard card = new CreditCard();
card.number = "1234567890123456";
IClassValidator classValidator = GetClassValidator(typeof(CreditCard));
InvalidValue[] invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(1, invalidValues.Length);
card.number = "541234567890125"; //right CC (luhn compliant)
invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(0, invalidValues.Length);
card.ean = "9782266156066";
invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(0, invalidValues.Length);
card.ean = "9782266156067";
invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(1, invalidValues.Length);
}

The breaking change is about the return value of GetInvalidValues : in NHV1.2.0 the method will return IEnumerable<InvalidValue>.

Refactoring step 1

Same but compileable.

[Test]
public void CreditCard()
{
CreditCard card = new CreditCard();
IClassValidator classValidator = GetClassValidator(typeof(CreditCard));

card.number = "1234567890123456";
Assert.That(classValidator.GetInvalidValues(card), Is.Not.Empty);

card.number = "541234567890125"; //right CC (luhn compliant)
Assert.That(classValidator.GetInvalidValues(card), Is.Empty);

card.ean = "9782266156066";
Assert.That(classValidator.GetInvalidValues(card), Is.Empty);

card.ean = "9782266156067";
Assert.That(classValidator.GetInvalidValues(card), Is.Not.Empty);
}
Refactoring step 2
[Test]
public void CreditCard()
{
CreditCard card = new CreditCard();
var classValidator = GetClassValidator(typeof(CreditCard));

card.number = "1234567890123456";
classValidator.GetInvalidValues(card).Should().Not.Be.Empty();

card.number = "541234567890125"; //right CC (luhn compliant)
classValidator.GetInvalidValues(card).Should().Be.Empty();

card.ean = "9782266156066"; //right EAN
classValidator.GetInvalidValues(card).Should().Be.Empty();

card.ean = "9782266156067"; //wrong EAN
classValidator.GetInvalidValues(card).Should().Not.Be.Empty();
}

Now, using SharpTestsEx, we can run the same test with xUnit, MsTests, MbUnit (if/when we will need/want change the unit test framework) and I can’t see where it is more verbose.

Refactoring step 3
[Test]
public void GivingValidState_NoInvalidValues()
{
var card = new CreditCard {Number = "541234567890125", Ean = "9782266156066"};
var classValidator = GetClassValidator(typeof(CreditCard));

classValidator.GetInvalidValues(card).Should().Be.Empty();
}

[Test]
public void GivingInvalidState_HasInvalidValues()
{
var card = new CreditCard {Number = "1234567890123456", Ean = "9782266156067"};
var classValidator = GetClassValidator(typeof(CreditCard));

classValidator.GetInvalidValues(card).Should().Have.Count.EqualTo(2);
}

Perhaps SharpTestsEx is a little bit more verbose, in some cases, but with your help we can improve it.

02 November 2009

Validation Abstraction: Custom

If you have read this post you know I’m having some psychological problem at work: multi-personality.

My dear friend Fabio-NHV said me: hey man! I have a very good OSS validation framework strongly recommended if you are validating entities you are using with NHibernate.

And I said: Cool!! but your framework is only an option for me… soon or later I’ll use something else and, btw, I need to mix the validation done by your framework with my BL and/or UI validation.

The IEntityValidator

The IEntityValidator is part of uNhAddIns because José asked me how I’m abstracting the validation stuff from my application, during the implementation of the ChinookMediamanager example (the same happened with the IGuyWire and, a year ago, with the CpBT and Gustavo).

public interface IEntityValidator
{
bool IsValid(object entityInstance);
IList<IInvalidValueInfo> Validate(object entityInstance);
IList<IInvalidValueInfo> Validate<T, TP>(T entityInstance, Expression<Func<T, TP>> property) where T : class;
IList<IInvalidValueInfo> Validate(object entityInstance, string propertyName);
}
public interface IInvalidValueInfo
{
Type EntityType { get; }
string PropertyName { get; }
string Message { get; }
}

any good validation-framework should give me the way to implement an adapter for, at least, these methods.

The implementation for NHibernate.Validator

We having an implementation of IEntityValidator in uNhAddIns… by the way, in an application in production, I’m using a more simple implementation:

public class NhVEntityValidator : IEntityValidator
{
private readonly ValidatorEngine validatorEngine;

public NhVEntityValidator(ValidatorEngine validatorEngine)
{
this.validatorEngine = validatorEngine;
}

#region Implementation of IEntityValidator

public bool IsValid(object entityInstance)
{
return validatorEngine.IsValid(entityInstance);
}

public IList<IInvalidValueInfo> Validate(object entityInstance)
{
InvalidValue[] iv = validatorEngine.Validate(entityInstance);
return
new
List<IInvalidValueInfo>(
from invalidValue in iv
select (IInvalidValueInfo) new InvalidValueInfo(invalidValue));
}

#endregion
}

public class InvalidValueInfo : IInvalidValueInfo
{
private readonly InvalidValue iv;

public InvalidValueInfo(InvalidValue iv)
{
this.iv = iv;
}

#region Implementation of IInvalidValueInfo

public Type EntityType
{
get { return iv.EntityType; }
}

public string PropertyName
{
get { return iv.PropertyName; }
}

public string Message
{
get { return iv.Message; }
}

#endregion
}

The Usage
As you can imagine the usage is simple. Where you need the IEntityValidator you must inject it:
public UsuarioParticularNuevoService(
    IDaoFactory factory,
IUserSessionContext context,
IMailSender mailSender,
IMailMaker mailMaker,
IEntityValidator entityValidator)

and then simply use it

public IInvalidValueInfo[] Register(UsuarioNuevoInfo usuarioInfo)
{
var usuario = GetUsuario(usuarioInfo);

AddPais(usuario);
AddDireccion(usuario, usuarioInfo);
AddTelefono(usuario, usuarioInfo);
AddNewsletter(usuario, usuarioInfo);
AddNegocio(usuario);

var errors = validator.Validate(usuario);

if (errors != null && errors.Count > 0)
return errors.ToArray();

usuarioDao.SaveOrUpdate(usuario);
mailSender.Send(GetMailMaker(usuarioInfo, usuario).Make());
return new IInvalidValueInfo[0];
}

The chunk, of the IoC’s configuration (in this case Castle.Windsor), in my dear IGuyWire look like:

ValidatorEngine validatorEngine = ConfigureNHibernateValidatorEngine();

container.Register(Component.For<ValidatorEngine>().Instance(validatorEngine));
container.Register(Component.For<ISharedEngineProvider>().ImplementedBy<SharedEngineProvider>());
NHibernate.Validator.Cfg.Environment.SharedEngineProvider =
container.Resolve<ISharedEngineProvider>();
container.Register(Component.For<IEntityValidator>().ImplementedBy<NhVEntityValidator>());

Options

In uNhAddIns you can find two more options, for the IEntityValidator, implemented for ValidationApplicationBlock and for DataAnnotation (thanks to José Romaniello for his implementation).

31 October 2009

Validation through persistence: not synchronized

In this series you saw mostly the configuration of NHibernate.Validator through Loquacious (our configuration based on fluent-interface).

What is the ValidationDef<T> ?

If you are using the Satisfier (validation through lambdas) the ValidationDef become the class whose responsibility is validate a instance of T.

If you need some validation, involving the persistence, and you want do it through NHV, which is the best candidate class where implement the validation ?

Let me show you how much easy is it:

public class BlogPostSofValidation : ValidationDef<BlogPost>
{
private readonly ISessionFactory factory;

public BlogPostSofValidation(ISessionFactory sessionFactory)
{
factory = sessionFactory;
ValidateInstance.By((bp, c) => !Exists(bp));
}

private bool Exists(BlogPost post)
{
if (ReferenceEquals(post, null))
{
return true;
}
using (var session = factory.OpenStatelessSession())
{
var criteria = session.CreateCriteria(typeof(BlogPost));
criteria.Add(Restrictions.Eq("Title", post.Title));
criteria.Add(Restrictions.Eq("Date", post.Date));
return criteria.UniqueResult() != null;
}
}
}

Here I’m showing only the part involving the persistence but you know… there you can define the validation of any other property as usual.

To register this definition the work to do is very easy:

var veConfig = new FluentConfiguration();
veConfig.Register(new BlogPostSofValidation(sessionFactory))
.SetDefaultValidatorMode(ValidatorMode.UseExternal);
validatorEngine = new ValidatorEngine();
validatorEngine.Configure(veConfig);

and that it’s all (the usage is identical of the previous post).

30 October 2009

Validation through persistence: synchronized

This post is about one possible answer to the question mememem ask me in this post (ah… nice nick).

The task is create a validator to validate the uniqueness, of an entity instance, using some properties’ values instead its POID (Persistence Object ID).

The implementation

public class BlogPost
{
public string Title { get; set; }
public DateTime Date { get; set; }
public string Content { get; set; }
}

we want check the uniqueness using the value of Title and the value of Date obviously without use both properties as composite-PK; so, we can’t have two posts with the same title in the same day.

Since NHibernate2.1.0GA we can instruct NH about our concept of uniqueness in a very explicit, self documented, and nice way:

<class name="BlogPost">
<
id type="guid">
<
generator class="guid.comb"/>
</
id>
<
natural-id mutable="true">
<
property name="Title"/>
<
property name="Date" type="Date"/>
</
natural-id>
<
property name="Content" type="string(10000)"/>
</
class>

clear no ? we are defining explicitly which is our natural-id, that mean we want a unique key with Title and Date. The result DDL is:

create table BlogPost (
id UNIQUEIDENTIFIER not null,
Title NVARCHAR(255) null,
Date DATETIME null,
Content NVARCHAR(MAX) null,
primary key (id),
unique (Title, Date)
)

We having NHibernate and the DataBase synchronized with the same rule and now we want create a validator to use with NHibernate.Validator to synchronize even our business logic (and prevent ADO.NET exceptions).

First the attribute to “mark” my classes:

[AttributeUsage(AttributeTargets.Class)]
[ValidatorClass(typeof(NaturalIdUniquenessValidator))]
public class NaturalIdUniquenessAttribute : Attribute, IRuleArgs
{
public string Message { get; set; }
}

then the validator implementation with NHibernate integration. In this implementation I’m using the Stateless-Session but you can use, a new statefull session or factory.GetCurrentSessionContext or whatever you have as session-provider. The matter is not from where you get the session but how create the query in a generic way that can be used for any entity without need any kind of “invasion” in my existing implementation.

Note: this is a classic usage of the stateless-session but take care with the BestGuessEntityName method.

public class NaturalIdUniquenessValidator : IValidator
{
private readonly ISessionFactory factory;

public NaturalIdUniquenessValidator(ISessionFactory sessionFactory)
{
factory = sessionFactory;
}

public bool IsValid(object value, IConstraintValidatorContext constraintContext)
{
if (ReferenceEquals(value, null))
{
return true;
}
using (var session = factory.OpenStatelessSession())
{
var entityName = ((ISessionImplementor) session).BestGuessEntityName(value);
var meta = factory.GetClassMetadata(entityName);
if (ReferenceEquals(meta, null) || !meta.HasNaturalIdentifier)
{
return true;
}
var propsValues = meta.GetPropertyValues(value, EntityMode.Poco);
var propsNames = meta.PropertyNames;
var criteria = session.CreateCriteria(entityName);
foreach (var propIdx in meta.NaturalIdentifierProperties)
{
criteria.Add(Restrictions.Eq(propsNames[propIdx], propsValues[propIdx]));
}
return criteria.UniqueResult() == null;
}
}
}

In the implementation I’m using some NHibernate advanced information to create a ICriteria with the properties defined as natural-id; the implementation is working with any entity of your domain. The strange thing, there, is another: the validator does not have a default constructor… where is the trick ?

Well… first the implementation with an home-made-2-minutes-IoC:

public class ConstraintValidatorFactory : DefaultConstraintValidatorFactory
{
public override IValidator GetInstance(Type type)
{
var persistenceCtor = type.GetConstructor(new[] {typeof (ISessionFactory)});
if(persistenceCtor != null)
{
return (IValidator)
persistenceCtor.Invoke(new object[] { NHibernateStaticContainer.Factory });
}
return base.GetInstance(type);
}
}

The IConstraintValidatorFactory is the factory for classes implementing IValidator and you can inject the concrete implementation through NHV configuration.

var nhvConfig = new FluentConfiguration();
nhvConfig.SetConstraintValidatorFactory<ConstraintValidatorFactory>();

Another, more generic, implementation of the IConstraintValidatorFactory could be:

public class ServiceLocatorValidatorFactory : DefaultConstraintValidatorFactory
{
#region Implementation of IConstraintValidatorFactory

public override IValidator GetInstance(Type type)
{
ConstructorInfo defaultConstructorInfo = type.GetConstructor(new Type[0]);
if (defaultConstructorInfo == null)
{
return (IValidator) ServiceLocator.Current.GetInstance(type);
}
return base.GetInstance(type);
}

#endregion
}

here you can use your preferred IoC framework as the factory/container of validators instances (take care with statefull validators).

The usage

Well… it is completely transparent, you can use this entity-validator as you are using any other.

the definition

public class BlogPostValidation: ValidationDef<BlogPost>
{
public BlogPostValidation()
{
ValidateInstance.Using(new NaturalIdUniquenessAttribute());
}
}

a simple test

var blogPost = new BlogPost
{
Title = "something new",
Date = DateTime.Today,
Content = "there is something new to say."
};

validatorEngine.IsValid(blogPost).Should().Be.True();

using (var s = sessionFactory.OpenSession())
using (var tx = s.BeginTransaction())
{
s.Save(blogPost);
tx.Commit();
}

var otherBlogPost = new BlogPost
{
Title = "something new",
Date = DateTime.Today,
Content = "bha?!?."
};

validatorEngine.IsValid(otherBlogPost).Should().Be.False();

otherBlogPost.Title = "very new";

validatorEngine.IsValid(otherBlogPost).Should().Be.True();

Conclusion

The implementation of the entity BlogPost was NEVER TOUCHED (I did it my way)… now :

  • go to your system
  • copy&paste the implementation of NaturalIdUniquenessAttribute and NaturalIdUniquenessValidator
  • change the implementation of the ConstraintValidatorFactory according to your system
  • change the mapping defining your natural-id in the entities where needed
  • Enjoy NHibernate.Validator, its flexibility, its injectability and its easy integration with NHibernate.

Tomorrow, perhaps, the no synchronized implementation.

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.

28 October 2009

NHibernate.Validator : Customizing messages (Message Interpolator)

The message interpolator is the responsible of the messages translation/composition. In the coming soon version (NHV-1.2.0) we had increase its power (and refactorized its implementation).

Has default NHV has two implementations: DefaultMessageInterpolatorAggregator and DefaultMessageInterpolator.

What is the usual you have seen in NHibernate’s eco-system ? Yes, you are right: Injectability!!!

So far the injectability in NHV is not so extreme as in NHibernate but we are closer…very closer ;)

If you only need to override some behavior you can inherit from DefaultMessageInterpolator. If you want implement a completely different way to create/translate/composite messages you can implements your own IMessageInterpolator.

In this post I will write about another case: the composition of your own behavior with the default behavior.

The needs

As you saw, in the previous post, we have solved the problem of magic-strings so and so…but was only for yesterday. Today I would manage all messages through my convention, and composite it only in the strings-resource-file, for all cases where possible.

The possible convention
  • The key for a class name will be : friendly.class.<TypeName> (ex.: friendly.class.Employee)
  • The key for a property name will be : friendly.property.<PropertyName> (ex: friendly.property.Salary) ; note: two properties with the same name should have the same meaning no matter which is the owner class (IMO).
  • The key for the message of a entity-validator (validate the instance) will be: validator.<TypeName>
  • The key for the message of a property-validator will be: validator.<TypeName>.<PropertyName>
  • The key for the message of a validator will be: validator.<ValidatorName>

For <ValidatorName> I mean the class name of the validator without the post-fix “Validator” (that is the convention used inside NHV).

There is a special case for the <ValidatorName> (as any good convention); using lambdas the implementation of the validator is ever the same so, in this case, the <TypeName> will be the type where the validation was specified.

Note: all reusable validators, using the Satisfier or not, should define its key.

Messages redefinition

In NHV the default message for the constraint NotNullNotEmpty is:

key: validator.notNullNotEmpty

value: may not be null or empty

what I would like is:

The [here the friendly name of the property] of the [here the friendly name of the entity] is mandatory.

The custom IMessageInterpolator

First I must define the syntax to use in my interpolator; there are three possible variables: [EntityName], [PropertyName], [PropertyValue]. In practice in my strings-resource-file I will have this:

CustomInterResource1

and in case I need a sub-property I would have something like this

CustomInterResource2

The implementation

public class ConventionMessageInterpolator : IMessageInterpolator
{
private const string EntityValidatorConvention = "{{validator.{0}}}";
private const string EntityPropertyValidatorConvention = "{{validator.{0}.{1}}}";
private const string EntityNameConvention = "{{friendly.class.{0}}}";
private const string PropertyNameConvention = "{{friendly.property.{0}}}";
private const string PropertyValueTagSubstitutor = "${{{0}{1}}}";
private static readonly int PropertyValueTagLength = "PropertyValue".Length;

private readonly Regex substitutions =
new Regex(@"\[EntityName\]|\[PropertyName\]|(\[PropertyValue([.][A-Za-z_][A-Za-z_0-9]*)*\])"
, RegexOptions.Compiled);

#region IMessageInterpolator Members

public string Interpolate(InterpolationInfo info)
{
string result = info.Message;
if(string.IsNullOrEmpty(result))
{
result = CreateDefaultMessage(info);
}
do
{
info.Message = Replace(result, info.Entity, info.PropertyName);
result = info.DefaultInterpolator.Interpolate(info);
}
while (!Equals(result, info.Message));
return result;
}

#endregion

public string
CreateDefaultMessage(InterpolationInfo info)
{
return string.IsNullOrEmpty(info.PropertyName) ?
string.Format(EntityValidatorConvention, GetEntityValidatorName(info))
:
string.Format(EntityPropertyValidatorConvention, info.Entity.Name, info.PropertyName);
}

private string GetEntityValidatorName(InterpolationInfo info)
{
var entityValidatorName = info.Entity.Name;
var validatorType = info.Validator.GetType();
if (validatorType.IsGenericType)
{
entityValidatorName = validatorType.GetGenericArguments().First().Name;
}
entityValidatorName = CleanValidatorPostfix(entityValidatorName);
return entityValidatorName;
}

private string CleanValidatorPostfix(string entityValidatorName)
{
var i = entityValidatorName.LastIndexOf("Validator");
return i > 0 ? entityValidatorName.Substring(0, i) : entityValidatorName;
}

public string Replace(string originalMessage, Type entity, string propName)
{
return substitutions.Replace(originalMessage, match =>
{
if ("[EntityName]".Equals(match.Value))
{
return string.Format(EntityNameConvention, entity.Name);
}
else if (!string.IsNullOrEmpty(propName) && "[PropertyName]".Equals(match.Value))
{
return string.Format(PropertyNameConvention, propName);
}
else if (!string.IsNullOrEmpty(propName) && match.Value.StartsWith("[PropertyValue"))
{
return string.Format(PropertyValueTagSubstitutor, propName,
match.Value.Trim('[', ']').Substring(PropertyValueTagLength));
}
return match.Value;
});
}
}

The configuration

To use both, my custom interpolator and my custom strings-resource-file the Loquacious configuration is:

var configure = new FluentConfiguration();
configure
.SetMessageInterpolator<ConventionMessageInterpolator>()
.SetCustomResourceManager("YourProd.Properties.ValidationMessagesConv", Assembly.Load("YourProd"))
.SetDefaultValidatorMode(ValidatorMode.UseExternal);

Results

Having a chunk of strings-resource-file as this

CustomInterResource3

I can write a clean definition like

public class AddressValidation: ValidationDef<IAddress>
{
public AddressValidation()
{
Define(a => a.Street).NotNullableAndNotEmpty();
Define(a => a.Number).GreaterThanOrEqualTo(1);
}
}

public class EntreCallesValidation : ValidationDef<IEntreCalles>
{
public EntreCallesValidation()
{
ValidateInstance.By(IsValid);
}

public bool IsValid(IEntreCalles subject, IConstraintValidatorContext context)
{
if(subject == null)
{
return true;
}
var calleA = subject.CalleA == null ? string.Empty : subject.CalleA.Trim();
var calleB = subject.CalleB == null ? string.Empty : subject.CalleB.Trim();
return !(string.Empty.Equals(calleA) ^ string.Empty.Equals(calleB));
}
}

public class DireccionArgentinaValidation: ValidationDef<DireccionArgentina>
{
public DireccionArgentinaValidation()
{
Define(da => da.CodigoPostal)
.MatchWith("[A-Z][0-9]{4}[A-Z]{3}")
.WithMessage("No es un codigo postal Argentino.");
}
}

public class EmployeePositionValidation : ValidationDefEx<EmployeePosition>
{
public EmployeePositionValidation()
{
const decimal avgSalary = 4000m;
const decimal salaryGap = 1500m;

Define(e => e.Description).NotNullableAndNotEmpty();
Define(ep => ep.Salary)
.IsValid()
.And
.NotEmpty()
.And
.GapLessThanOrEqualTo(salaryGap)
.And
.Include(avgSalary);
}
}

public class StandUpMeetingValidation : ValidationDefEx<StandUpMeeting>
{
public StandUpMeetingValidation()
{
TimeSpan meetingTime = TimeSpan.FromMinutes(20);

Define(m => m.Lapse)
.IsValid()
.And
.NotEmpty()
.And
.Satisfy(
r => (new Range<DateTime>
{
LowLimit = r.LowLimit.Date.AddHours(9),
HighLimit = r.LowLimit.Date.AddHours(17).AddMinutes(30)
}).Includes(r)
)
.WithMessage("{validator.StandUpMeeting.Lapse.WorkingTime}")
.And
.GapLessThanOrEqualTo(meetingTime);
}
}

public class EmployeeValidation : ValidationDef<Employee>
{
public EmployeeValidation()
{
Define(e => e.Name).NotNullableAndNotEmpty()
.And
.LengthBetween(2, 30);

Define(e => e.Salary).GreaterThanOrEqualTo(1000m);
}
}

to have invalid messages as:

Must specify both streets or none.
No es un codigo postal Argentino.
The street of the address is mandatory.
The number must be greater than or equal to 1

The description of the employee position is mandatory.
The rage salary should include:4000

The meeting should happen in working time.
The duration of standup-meeting was too long. Expected less than :00:20:00

with all advantages a strings-resource-file, give me.

27 October 2009

NHibernate.Validator : Customizing messages (bases)

One of the most powerful feature of NHibernate.Validator is its way to manage messages.

In this post are the bases of the massage customization.

The Price

In the last moth this blog was visited from 101 countries but NHibernate.Validator has only 8 translations. The available cultures are: en, es, it, fr, de, nl, lv, pl. Are you seeing the translation in your language ? you don’t ? What you are waiting for ?!!?!!?

From now on, feel in debt with us if you never sent the patch with the translation for your country. Now you can continue reading… ;)

The Message

The message represent what you want show to the user for an invalid value. For example:

public class EmployeeValidation : ValidationDef<Employee>
{
public EmployeeValidation()
{
Define(e => e.Name).NotNullableAndNotEmpty()
.WithMessage("The name of the employee is mandatory.")
.And
.LengthBetween(2,30)
.WithMessage("The length of the name of the employee should be between 2 and 30.");

Define(e => e.Salary).GreaterThanOrEqualTo(1000m)
.WithMessage("The salary should be greater than $1000.");
}
}

Without talk about multi-languages applications let me analyze these messages.

  1. First of all we have three beautiful magic-strings.
  2. If I want be more clear and instead print “name” I want “full name” I must remember to do it in the message of NotNullableAndNotEmpty and in the message of LengthBetween.
  3. If I want print “is mandatory” for any other NotNullableAndNotEmpty usage I must repeat it everywhere.
  4. If I need to change the limits in the LengthBetween constraint and in the GreaterThanOrEqualTo I must remember to change it even in the message.
  5. And if I want to print the actual length of the Name property in the message of LengthBetween constraint ? what should I do ?

The Message definition syntax

To make it short any valid string is a valid message and there are two special cases:

<EmbeddedValue> ::= ‘{’ <Identifier> ‘}’

<PropertyValue> ::= ‘$’‘{’ <PropertyPath> ‘}’

Embedded Value: The embedded value syntax is to solve some of above problems (p1, p2, p3, p4).

Property Value: The property value syntax is to solve p4.

Our RegEx, to recognize valid tokens, is: (?<![#])[$]?{(\w|[._0-9])*}

The Message composition

To solve the p2 and p3 : "The {friendly.property.name} of the employee {validator.NotNullableAndNotEmpty}."

Defined as is, NHV will look in a strings-resource-file (example below) for the value which key is “friendly.property.name” and then for for a value which key is “validator.NotNullableAndNotEmpty”.

If in the strings-resource-file we have :

CustomResource1


The translated message will be: The full name of the employee is mandatory.

To solve p4: "The length of the {friendly.property.name} of the employee should be between {Min} and {Max} characters."

If we look at the Attribute, linked to LengthBetween constraint, we will find that it has two public properties named exactly:

public int Min { get; set; }
public int Max
{
get { return max; }
set { max = value; }
}

So, defined as is, NHV will look in a strings-resource-file for the value which key is “friendly.property.name” and then will look to the public properties of the Attribute, linked to the constraint, to find the value of the property named Min and the property named Max.

Having the above entries, in our strings-resource-file, and giving Min=2 and Max=30 the translated message will be: The length of the full name of the employee should be between 2 and 30 characters.

To solve the p1: this point, perhaps, is more useful if you are developing a multi language application by the way…

Having

CustomResource2

your definition may look as:

public EmployeeValidation()
{
Define(e => e.Name).NotNullableAndNotEmpty()
.WithMessage("{message.employee.name.NotNullableAndNotEmpty}")

Note that the value of “message.employee.name.NotNullableAndNotEmpty” is composed by others variables and NHV will resolve everything recursively.

To solve p5: well… at this point you can imagine that what we need is only use the PropertyValue syntax… but a property of what ?

The property represent a full-property-path starting from the object under validation; that mean that giving a definition as:

.LengthBetween(2,30)
.WithMessage("{message.employee.name.length}");

and a strings-resource-file as

CustomResource3

running

var employee = new Employee {Name = new string('A',31) };
var iv = validatorEngine.Validate(employee);

the message of the invalid value will be:

The full name of the employee should have length between 2 and 30 characters but is 31.

The Resource bundle

How create a strings-resource-file (for mono/multi language applications) is outside the scope of this post; you can find more information starting from this link.

After create the file I have only one recommendation : immediately remove the auto-generated Resource.cs and then clean the property “Custom Tool” from the properties of the file (F4).

To configure your own strings-resource-file you can use

var configure = new FluentConfiguration();
configure.SetCustomResourceManager("YourAssmbly.Properties.ValidationMessages", Assembly.LoadFrom("YourAssembly"))

or

<property name='resource_manager'>
YourFullNameSpace.TheBaseNameOfTheResourceFileWithoutExtensionNorCulture, YourAssembly
</property>
The rules are the same of the ResourceManager class.

Conclusion

Perhaps you think we haven’t solved the problem of magic-strings, but is because define a good convention for message-naming is in your charge.

Perhaps you think “Man!! if I don’t need multi-language I want avoid all those ‘message.class.prop.constraint’ and I prefer to write the message directly.”

Perhaps you think “Man!! I need multi-language but all those ‘message.class.prop.constraint’ really annoys me.”

take it easy ;-)… the story does not end here…

26 October 2009

NHibernate.Validator : Extending ValidationDef

In various applications I’m using my implementation of Range.

public interface IRange<T> : IEquatable<IRange<T>> where T : IComparable<T>
{
T LowLimit { get; }
T HighLimit { get; }
bool IsEmpty { get; }
bool Includes(T value);
bool Includes(IRange<T> other);
bool Overlaps(IRange<T> other);
}

As you can imagine I’m using it to represent various kind of ranges and in each usage I need to validate the range in various ways. Two simply examples:

public class EmployeePosition
{
public string Description { get; set; }
public IRange<decimal> Salary { get; set; }
}

public class StandUpMeeting
{
public ICollection<Employee> Employees { get; set; }
public IRange<DateTime> Lapse { get; set; }
}

To validate IRange<T> properties, through NHV-loquacious-configuration, I can’t extend some NHV’s interfaces because NHV doesn’t know my type (IRange<T>) and a simple entity-validator (as showed here) is not enough because I need to validate various situation of the range; the way to go is create my own set of constraints.

Custom constraints (extending ValidationDef)

public interface IRangeConstraints<T> : ISatisfier<IRange<T>, IRangeConstraints<T>>
where T : IComparable<T>
{
IChainableConstraint<IRangeConstraints<T>> IsValid();
IChainableConstraint<IRangeConstraints<T>> NotEmpty();
IChainableConstraint<IRangeConstraints<T>> Include(T value);
IChainableConstraint<IRangeConstraints<T>> Include(IRange<T> range);
IChainableConstraint<IRangeConstraints<T>> Overlaps(IRange<T> range);
}

Defined the interface I need an entry point to integrate it with the Loquacious configuration. The “natural” extension-point seems the class ValidationDef<T>. There are various way to extend the ValidationDef<T> but in my opinion the most clear, the most useful and the most easy is a simple inheritance.

public class ValidationDefEx<T> : ValidationDef<T> where T : class
{
public IRangeConstraints<decimal> Define(Expression<Func<T, IRange<decimal>>> property)
{
return null;
}

public IRangeConstraints<DateTime> Define(Expression<Func<T, IRange<DateTime>>> property)
{
return null;
}
}

Now I’m ready to check the API.

public class EmployeePositionValidation : ValidationDefEx<EmployeePosition>
{
public EmployeePositionValidation()
{
const decimal avgSalary = 4000m;

Define(e => e.Description).NotNullableAndNotEmpty();
Define(ep => ep.Salary)
.IsValid()
.WithMessage("The {property.salary} should be valid but was ${Salary}.")
.And
.NotEmpty()
.And
.Include(avgSalary)
.WithMessage("The {property.salary} should be around " + avgSalary);
}
}

public class StandUpMeetingValidation : ValidationDefEx<StandUpMeeting>
{
public StandUpMeetingValidation()
{
Define(m => m.Lapse)
.IsValid()
.WithMessage("The {property.lapse} should be valid but was ${Lapse}.")
.And
.NotEmpty();
}
}

The base API work fine; I can go to tests and implementation.

public class RangeConstraints<TR> : BaseConstraints<IRangeConstraints<TR>>, IRangeConstraints<TR>
where TR : IComparable<TR>
{
#region Implementation of IRangeConstraints<TR>

public RangeConstraints(IConstraintAggregator parent, MemberInfo member) : base(parent, member) {}

public IChainableConstraint<IRangeConstraints<TR>> IsValid()
{
return Satisfy(r => r.LowLimit.CompareTo(r.HighLimit) <= 0)
.WithMessage("{validator.range.IsValid}");
}

public IChainableConstraint<IRangeConstraints<TR>> NotEmpty()
{
return Satisfy(r => !r.IsEmpty)
.WithMessage("{validator.range.NotEmpty}");
}

public IChainableConstraint<IRangeConstraints<TR>> Include(TR value)
{
return Satisfy(r => r.Includes(value))
.WithMessage("{validator.range.Include}" + value);
}

public IChainableConstraint<IRangeConstraints<TR>> Include(IRange<TR> range)
{
return Satisfy(r => r.Includes(range))
.WithMessage("{validator.range.Include}" + range);
}

public IChainableConstraint<IRangeConstraints<TR>> Overlaps(IRange<TR> range)
{
return Satisfy(r => r.Overlaps(range))
.WithMessage("{validator.range.Overlaps}" + range);
}

#endregion

#region
Implementation of ISatisfier<IRange<TR>,IRangeConstraints<TR>>

public IChainableConstraint<IRangeConstraints<TR>> Satisfy(Func<IRange<TR>, IConstraintValidatorContext, bool> isValidDelegate)
{
var attribute = new DelegatedValidatorAttribute(new DelegatedConstraint<IRange<TR>>(isValidDelegate));
return AddWithConstraintsChain(attribute);
}

public IChainableConstraint<IRangeConstraints<TR>> Satisfy(Func<IRange<TR>, bool> isValidDelegate)
{
var attribute = new DelegatedValidatorAttribute(new DelegatedSimpleConstraint<IRange<TR>>(isValidDelegate));
return AddWithConstraintsChain(attribute);
}

#endregion
}

and the my validation definition extension look like

public class ValidationDefEx<T> : ValidationDef<T> where T : class
{
public IRangeConstraints<decimal> Define(Expression<Func<T, IRange<decimal>>> property)
{
return new RangeConstraints<decimal>(this, TypeUtils.DecodeMemberAccessExpression(property));
}

public IRangeConstraints<DateTime> Define(Expression<Func<T, IRange<DateTime>>> property)
{
return new RangeConstraints<DateTime>(this, TypeUtils.DecodeMemberAccessExpression(property));
}
}

Work done!! Now I have my own set of constraints for my IRange<T> and I can use it with NHV.

Ups!!! … new request: I must validate the gap of the Salary and the time of the standup-meeting.

Extending the Extension

public static class RangeConstraintsExtensions
{
public static IChainableConstraint<IRangeConstraints<decimal>>
GapLessThanOrEqualTo(this IRangeConstraints<decimal> definition, decimal value)
{
return
definition.Satisfy(r => r.HighLimit - r.LowLimit <= value)
.WithMessage("{validator.range.GapLessThanOrEqualTo}" + value);
}

public static IChainableConstraint<IRangeConstraints<decimal>>
GapGreaterThanOrEqualTo(this IRangeConstraints<decimal> definition, decimal value)
{
return
definition.Satisfy(r => r.HighLimit - r.LowLimit >= value)
.WithMessage("{validator.range.GapGreaterThanOrEqualTo}" + value);
}

public static IChainableConstraint<IRangeConstraints<DateTime>>
GapLessThanOrEqualTo(this IRangeConstraints<DateTime> definition, TimeSpan value)
{
return
definition.Satisfy(r => r.HighLimit - r.LowLimit <= value)
.WithMessage("{validator.TimeRange.GapLessThanOrEqualTo}" + value);
}

public static IChainableConstraint<IRangeConstraints<DateTime>>
GapGreaterThanOrEqualTo(this IRangeConstraints<DateTime> definition, TimeSpan value)
{
return
definition.Satisfy(r => r.HighLimit - r.LowLimit >= value)
.WithMessage("{validator.TimeRange.GapGreaterThanOrEqualTo}" + value);
}
}

And now my two definitions can look like

public class EmployeePositionValidation : ValidationDefEx<EmployeePosition>
{
public EmployeePositionValidation()
{
const decimal avgSalary = 4000m;
const decimal salaryGap = 1500m;

Define(e => e.Description).NotNullableAndNotEmpty();
Define(ep => ep.Salary)
.IsValid()
.WithMessage("The {property.salary} should be valid but was ${Salary}.")
.And
.NotEmpty()
.And
.GapLessThanOrEqualTo(salaryGap)
.WithMessage("The gap of {property.salary} should be " + salaryGap)
.And
.Include(avgSalary)
.WithMessage("The {property.salary} should be around " + avgSalary);
}
}

public class StandUpMeetingValidation : ValidationDefEx<StandUpMeeting>
{
public StandUpMeetingValidation()
{
TimeSpan meetingTime = TimeSpan.FromMinutes(20);

Define(m => m.Lapse)
.IsValid()
.WithMessage("The {property.lapse} should be valid but was ${Lapse}.")
.And
.NotEmpty()
.And
.Satisfy(
r =>(new Range<DateTime>
{
LowLimit = r.LowLimit.Date.AddHours(9),
HighLimit = r.LowLimit.Date.AddHours(17).AddMinutes(30)
}).Includes(r)
)
.WithMessage("The meeting should happen during working time")
.And
.GapLessThanOrEqualTo(meetingTime)
.WithMessage("The {entity.StandUpMeeting} was too long.");
}
}

Conclusion

Now you know one reason because NHibernate.Validator is part of my Gum-Architecture: it is compressible, extensible, ball-able, cube-able, flat-able… ;) and the story does not end here...