Menu

Multi-Property Validation Attribute with EF Code First

February 17, 2015 by Christopher Sherman

Entity Framework provides several built-in validators for individual properties on Code First models. When you want to validate multiple, dependent properties, however, in most cases you will need to create a custom, class-level validation attribute. In this tutorial, I’ll explain how to do just that.

In the model below, I have a SurplusRequest Code First model with properties that include Barcode and Quantity. At the top of the class is the custom validation attribute we’ll build in the next step.

using SurplusPrototype.DataAccess;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace YourProjectName.Models
{
[CustomValidation(typeof(FixedAssetValidationAttribute), "HasValidFixedAssetQuantity")]
public class SurplusRequest
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }

        [Required]
        [StringLength(9)]
        [Display(Name = "Asset number")]
        public string Barcode { get; set; }

        // Other properties.

        public int Quantity { get; set; }
    }

}

I would like to validate that the Quantity equals one when the Barcode property is set. To do this, I create a class that inherits from ValidationAttribute named FixedAssetValidationAttribute.cs.

To this class I add a static method named HasValidFixedAssetQuantity. The method first checks to see whether the request is for a fixed asset; this check is made against a sentinel value I defined in my Web.config. Assuming the request is for a fixed asset, the next check validates that the quantity equals one.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using SurplusPrototype.Models;
using System.Web.Configuration;

namespace YourProjectName.DataAccess
{
[Serializable][attributeusage(attributetargets.property, allowmultiple = false, inherited = true)]
public class FixedAssetValidationAttribute : ValidationAttribute
{
public static ValidationResult HasValidFixedAssetQuantity(SurplusRequest surplusRequest)
{
var barcode = surplusRequest.Barcode;
if (barcode == WebConfigurationManager
.AppSettings["notFixedAssetSentinel"])
{
return ValidationResult.Success;
}
else if (surplusRequest.Quantity == 1)
{
return ValidationResult.Success;
}

            return new ValidationResult("Fixed assets must have a " +
                "quantity equal to one.", new List() { "Quantity" });
        }
    }

}

As you can see, if see neither check evaluates to true, this means the request is for a fixed asset with a quantity not equal to one, failing the validation. As a result, I return a message indicating the failure, as well as the property on which the failed validation message should appear.

With the custom validation attribute class implemented, the final step is to decorate the model class with the custom validation annotation as you saw in the model above. The first annotation parameter is the validation attribute class name, and the second parameter is the name of the validation method.

[CustomValidation(typeof(FixedAssetValidationAttribute), "HasValidFixedAssetQuantity")]

Entity Framework C-Sharp