In the previous recipe, we saw how to decorate our entity classes with NHibernate Validator. A better practice is to extract your validation rules to separate classes and avoid this dependency. In this recipe, we'll show you how to create validator classes, as well as an alternative method for configuring NHibernate Validator.
Complete the Eg.Core
model and mappings from Chapter 1, The Configuration and Schema.
Eg.ClassValidation
.Eg.Core
model.Install-Package NHibernate.Validator
ProductValidation
class:public class ProductValidator : ValidationDef<Product> { public ProductValidator() { Define(p => p.Name) .NotNullableAndNotEmpty() .And.MaxLength(255); Define(p => p.Description) .NotNullableAndNotEmpty(); Define(p => p.UnitPrice) .GreaterThanOrEqualTo(0M) .WithMessage("Unit price can't be negative."); } }
Eg.ClassValidation.Runner
.Eg.ClassValidation.Runner
project using NuGet Package Manager Console by running the following command:Install-Package NHibernate Install-Package NHibernate.Validator Install-Package log4net
App.config
with the standard log4net
and hibernate-configuration
sections, following the Configuring NHibernate with App.config and Configuring NHibernate logging recipes from Chapter 1, The Configuration and Schema.BasicSharedEngineProvider
using the following code:public class BasicSharedEngineProvider : ISharedEngineProvider { private readonly ValidatorEngine ve; public BasicSharedEngineProvider(ValidatorEngine ve) { this.ve = ve; } public ValidatorEngine GetEngine() { return ve; } public void UseMe() { Environment.SharedEngineProvider = this; } }
Program.cs
, use the following code:private static void Main(string[] args) { XmlConfigurator.Configure(); var log = LogManager.GetLogger(typeof (Program)); SetupNHibernateValidator(); var nhibernateConfig = new Configuration().Configure(); nhibernateConfig.Initialize(); ISessionFactory sessionFactory = nhibernateConfig. BuildSessionFactory(); var schemaExport = new SchemaExport(nhibernateConfig); schemaExport.Execute(false, true, false); var junk = new Product { Name = "Spiffy Junk", Description = string.Empty, UnitPrice = -1M }; var ve = Environment.SharedEngineProvider.GetEngine(); var invalidValues = ve.Validate(junk); foreach (var invalidValue in invalidValues) { log.InfoFormat("{0} {1}", invalidValue.PropertyName, invalidValue.Message); } } private static FluentConfiguration GetNhvConfiguration() { var nhvConfiguration = new FluentConfiguration(); nhvConfiguration .SetDefaultValidatorMode(ValidatorMode.UseExternal) .Register(Assembly.Load("Eg.ClassValidation") .ValidationDefinitions()) .IntegrateWithNHibernate .ApplyingDDLConstraints() .And.RegisteringListeners(); return nhvConfiguration; } private static ValidatorEngine GetValidatorEngine() { var cfg = GetNhvConfiguration(); var validatorEngine = new ValidatorEngine(); validatorEngine.Configure(cfg); return validatorEngine; } private static void SetupNHibernateValidator() { var validatorEngine = GetValidatorEngine(); new BasicSharedEngineProvider(validatorEngine).UseMe(); }
In this recipe, we have separated our validation rules into a separate class named ProductValidation
. Just as we did in our previous recipe, we have decided that each valid Product
must have a non-null, non-empty Name
, a Description
(not more than 255 characters long), and a non-negative UnitPrice
.
As we learned in the previous recipe, we use an ISharedEngineProvider
to locate our validation engine.
Unlike the previous recipe, we use the loquacious, or fluent, syntax to configure NHibernate Validator.
We validate our junk Product
. It fails two validation rules. First, the Description
can't be empty. Second, the UnitPrice
can't be negative. As we see in the log4net output, we get the following validation error messages:
Description may not be null or empty
UnitPrice can't be negative
We can also use NHibernate Validator to validate an entire object graph. Let's take our Movie entity as an example. Suppose we want to ensure that the movie entity is valid, as well as all of its ActorRole children. Our validation class would appear as shown:
Define(m => m.Director) .NotNullableAndNotEmpty() .And.MaxLength(255); Define(m => m.Actors) .HasValidElements();
The HasValidElements
runs the ActorRole validation rules on each object in the Actors
collection.
18.220.202.209