Search code examples
nhibernateasp.net-mvc-3s#arp-architecturenhibernate-validator

NHiberate Validator start date before end date


Using Nhibernate Validator (with S#harp Architecture / MVC3), how can I write a custom attribute, preferably not object-specific (since this is a fairly common requirement) that enforces that PropertyA >= PropertyB (or in the more general case, both may be null).

Something like

public DateTime? StartDate { get; set; }

[GreaterThanOrEqual("StartDate")]
public DateTime? EndDate { get; set; }

I see that I can override IsValid in the particular Entity class but I wasn't sure if that was the best approach, and I didn't see how to provide a message in that case.


Solution

  • When you need to compare multiple properties of an object as part of validation, you need a claass validator. The attribute is then applied to the class, not the property.

    I don't think there is an existing one to do what you want, but it is easy enough to write your own.

    Here is a code outline to show you roughly what your validator could look like

    [AttributeUsage(AttributeTargets.Class)]
    [ValidatorClass(typeof(ReferencedByValidator))]
    public class GreaterThanOrEqualAttribute : EmbeddedRuleArgsAttribute, IRuleArgs
    {        
        public GreaterThanOrEqualAttribute(string firstProperty, string secondProperty)
        {
            /// Set Properties etc
        }
    }
    
    public class ReferencedByValidator : IInitializableValidator<GreaterThanOrEqualAttribute>
    {       
        #region IInitializableValidator<ReferencedByAttribute> Members
    
        public void Initialize(GreaterThanOrEqualAttribute parameters)
        {
            this.firstProperty = parameters.FirstProperty;
            this.secondProperty = parameters.SecondProperty;
        }
    
        #endregion
    
        #region IValidator Members
    
        public bool IsValid(object value, IConstraintValidatorContext constraintContext)
        {
           // value is the object you are trying to validate
    
            // some reflection code goes here to compare the two specified properties
       }
        #endregion
    
    }
    

    }