Enterprise Library ValueValidator for NHibernate unique values

30 October 2008 14:34

Mouthful of a title...  So the background story is the need to check uniqueness of a value against the existing database of values during the Enterprise Library (v4.0) validation (and before the DB constraint violation), oh and I'm using NHibernate (v2.0) for persistence.  I decided to to create a ValueValidator to allow the application of rule by config or attribute rather than implement as self validation. Straight to it then. I will list the full class later but to help explain the cocky bit these are the main methods:

private bool IsUnique(Type targetType, string propertyName, object propertyValue, object validatedObject)
{
    using (ISession session = m_factory.OpenSession())
    {
        int matches = (int)session.CreateCriteria(targetType)
            .Add(Expression.Eq(propertyName, propertyValue))
            .Add(Expression.Not(EqualIdentifier(targetType, validatedObject)))
            .SetProjection(Projections.ProjectionList()
                .Add(Projections.RowCount()))
            .UniqueResult();
        return (matches == 0);
    }
}
private SimpleExpression EqualIdentifier(Type targetType, object validatedObject)
{
    ISessionFactoryImplementor factoryImplementor = (ISessionFactoryImplementor)m_factory;
    IEntityPersister persister = factoryImplementor.GetEntityPersister(targetType);
    object idPropertyValue = persister.GetIdentifier(validatedObject, EntityMode.Poco);
    string idPropertyName = persister.IdentifierPropertyName;
    return Expression.Eq(idPropertyName, idPropertyValue);
}

The IsUnique method is called within the DoValidate of the ValueValidator, it constructs a criteria query to basically select count(*) from table where unique property = value and not key column = key value - with the identifier detail returned as a SimpleExpression from the  EqualIdentifier method using the objects persister.  Actually pretty simple and sweet!  Full code for the validator:

public class UniqueValueValidator : ValueValidator
{
    private ISessionFactory m_factory;
    public UniqueValueValidator(string messageTemplate, string tag, bool negated)
        : base(messageTemplate, tag, negated)
    {
        Configuration config = new Configuration().Configure();
        m_factory = config.BuildSessionFactory();
    }
    protected override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults)
    {
        Type targetType = GetTargetType(currentTarget);
        object target = GetTargetObject(currentTarget);
        if (!IsUnique(targetType, key, objectToValidate, target))
            validationResults.AddResult(new ValidationResult(key + " must be unique", currentTarget, key, base.Tag, this));
    }
    private bool IsUnique(Type targetType, string propertyName, object propertyValue, object validatedObject)
    {
        using (ISession session = m_factory.OpenSession())
        {
            int matches = (int)session.CreateCriteria(targetType)
                .Add(Expression.Eq(propertyName, propertyValue))
                .Add(Expression.Not(EqualIdentifier(targetType, validatedObject)))
                .SetProjection(Projections.ProjectionList()
                    .Add(Projections.RowCount()))
                .UniqueResult();
            return (matches == 0);
        }
    }
    private SimpleExpression EqualIdentifier(Type targetType, object validatedObject)
    {
        ISessionFactoryImplementor factoryImplementor = (ISessionFactoryImplementor)m_factory;
        IEntityPersister persister = factoryImplementor.GetEntityPersister(targetType);
        object idPropertyValue = persister.GetIdentifier(validatedObject, EntityMode.Poco);
        string idPropertyName = persister.IdentifierPropertyName;
        return Expression.Eq(idPropertyName, idPropertyValue);
    }
    private Type GetTargetType(object currentTarget)
    {
        if (currentTarget == null)
            throw new ArgumentException("Target should not be null");
        if (currentTarget is IValidationIntegrationProxy)
            return (currentTarget as IValidationIntegrationProxy).ValidatedType;
        return currentTarget.GetType();
    }
    private object GetTargetObject(object currentTarget)
    {
        if (currentTarget == null)
            throw new ArgumentException("Target should not be null");
        if (currentTarget is IValidationIntegrationProxy)
            return (currentTarget as IValidationIntegrationProxy).GetRawValue();
        return currentTarget;
    }
    protected override string DefaultNegatedMessageTemplate
    {
        get { return "The value must be unique"; }
    }
    protected override string DefaultNonNegatedMessageTemplate
    {
        get { return "The value must be unique"; }
    }
}

and for the attribute:

public class UniqueValueValidatorAttribute : ValueValidatorAttribute
{
    protected override Validator DoCreateValidator(Type targetType)
    {
        return new UniqueValueValidator(MessageTemplate, Tag, Negated);
    }
}
Which means that you can add the UniqueValueValidator attribute to properties to enforce unique value during validation:
        [UniqueValueValidator]
        public virtual string Name { get; set; }


Powered by BlogEngine.NET 1.1.2.9

Calendar

<<  May 2013  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar

Search

Disclaimer

The opinions expressed in this blog are my own personal opinions and (for legal reasons) are not necessarily the views of anyone else (probably in the world) and particularly my employer!

Sign in

E-mail me Send mail

© Copyright 2013