Apr 27

The S#arp framework: the duplicate entity validator

Posted in S#arp      Comments Off on The S#arp framework: the duplicate entity validator

In the last post I promise that we’d talk about the EntityDuplicateChecker and that’s what we’re going to look at today. As we’ll see, this  class is used by the custom NH validators  that you can find in the SharpArch.Core.NHibernateValidator. The EntityDuplicateChecker implements the IEntityDuplicateChecker, which looks like this:

public interface IEntityDuplicateChecker    {
        bool DoesDuplicateExistWithTypedIdOf<IdT>(IEntityWithTypedId<IdT> entity);

The EntityDuplicateChecker’s responsibility is to search for an entity with the same business signature as the IEntityWithTypedId instance that was passed in and that has a different Id.The current implementation of this interface is not really complicated since it relies on getting all the properties used in the business signature (which you can get by calling EntityWithTypedId’s GetSignatureProperties method) and adding a restriction for each to the ISession that is used for interacting with the database.

As you might expect (if you’ve been following along), the ISession is obtained by using the NHibernateSession.Current property which we’ve met in one of the latest posts. Now, even though you can use this class directly in your code, the truth is that you’ll probably end up using the custom HasUniqueDomainSignatureAttribute (if you’re using NH Validator for your domain validation, that is). Whenever you need to add a custom NH Validation rule, you need to add (at least) two classes: one new custom attribute and  a new validator class. Let’s start with the custom attribute…

The S#arp framework introduces the HasUniqueDomainSignatureAttribute, which is really simple and looks like this:

public class HasUniqueDomainSignatureAttribute : Attribute, IRuleArgs    {
        public string Message {
            get { return message; }
            set { message = value; }

        private string message = "Provided values matched an existing, duplicate entity";

As you can see, the attribute implements the IRuleArgs:

public interface IRuleArgs    {
   string Message { get; set; }

This interface’s only objective is to let you get or set the error message that should be shown when there’s an error. Another interesting thing (from the previous snippet) is the use of the ValidatorClassAttribute. This is used to indicate the type of the validator class that is really responsible for performing the validation of that value. In this case,validation is performed by the HasUniqueDomainSignatureValidator class,which implements the mandatory IValidator interface. Here’s the current code for this class:

public class HasUniqueDomainSignatureValidator : NHibernate.Validator.Engine.IValidator    {
        public bool IsValid(object value) {
            IEntityWithTypedId<int> entityToValidate = value as IEntityWithTypedId<int>;
            Check.Require(entityToValidate != null,
                "This validator must be used at the class level of an " +
                "IdomainWithTypedId<int>. The type you provided was " + value.GetType().ToString());

            IEntityDuplicateChecker duplicateChecker = SafeServiceLocator<IEntityDuplicateChecker>.GetService();
            return ! duplicateChecker.DoesDuplicateExistWithTypedIdOf<int>(entityToValidate);

As you can see, the class has only one method which relies on the service locator for getting a  valid instance of the IEntityDuplicateChecker that is responsible for validation. If you look at the source code, you’ll see that there are other pairs attribute/validator for validating specific types of database keys (you have one pair for strings and another for Guids, so use those instead of the general one I’ve shown if you’re using a strings or a Guids for keys).

Don’t forget that to use this custom validation attribute, you need to register the EntityDuplicateChecker with the ServiceLocator. If you don’t, validation won’t work!

And that’s all for today. Keep tuned for more about the S#arp framework.