Good Night Nerd Pride
Good Night Nerd Pride

Reputation: 8490

Get Type of ValidationAttribute causing a DbEntityValidationException

I'm using the validation of the Entity Framework which relies on System.ComponentModel.DataAnnotations.ValidationAttributes. So when I call DbContext.SaveChanges() and an entity property fails validation, a DbEntityValidationException is thrown.

What I need to know is which ValidationAttribute exactly caused that validation error. I.e. I need to know the Type of ValidationAttribute causing the DbEntityValidationException within my program.

I already know how to iterate through the collections of validation errors inside the DbEntityValidationException. However the required information is not in there.


Example

Say I have this simple model with a single property which has two data annotations...

class Model
{
    [Required]
    [MaxLength(3)]
    string Code { ... }
}

...and want to add a new instance of it like so:

try
{
    var model = new Model { Code = "ThisIsTooLong" };
    dbContext.Set<Model>().Add(model);
    dbContext.SaveChanges();
}
catch (DbEntityValidationException e)
{
    Type unsatisfiedValidationAttribute = MagicFunction();
}

In the above case an DbEntityValidationException is thrown and the variable unsatisfiedValidationAttribute should be equal to typeof(MaxLengthAttribute).

What does MagicFunction() has to do to know whether the Required or the MaxLength annotation triggered the validation error?

Upvotes: 4

Views: 1087

Answers (2)

ocuenca
ocuenca

Reputation: 39376

I think what you looking for is Validator.TryValidateObject static method:

var modelToSave = new Model { Code = "ThisIsTooLong" };
var results = new List<ValidationResult>();
bool isValid=Validator.TryValidateObject( modelToSave, context, results, true);

In case your entity is not valid you are going to hold each failed validation in results list.

Update

Well, a generic solution to get the ValidationAttribute using the ErrorMessage could be doing this:

public static ValidationAttribute GetAttribute(Type entityType, string property, string errorMessage)
{
   var attributes = typeof(entityType)
                   .GetProperty(property)
                   .GetCustomAttributes(false)
                   .OfType<ValidationAttribute>()
                   .ToArray();
   var attribute= attributes.FirstOrDefault(a => a.ErrorMessage == errorMessage);
   return attribute;
} 

Upvotes: 1

Ehsan
Ehsan

Reputation: 367

This might help you If you are using Entity Framework 4.1+. You can implement your own validation logic in your entity and return your own error codes for different validation issues.

IValidatableObject is an interface that lives in System.ComponentModel.DataAnnotations. While it is not part of the Entity Framework API, you can still leverage it for server-side validation in your Entity Framework classes. IValidatableObject provides a Validate method that Entity Framework will call during SaveChanges or you can call yourself any time you want to validate the classes.
Configurations such as Required and MaxLength perform validaton on a single field. In the Validate method you can have even more complex logic, for example, comparing two fields.

public class Blog : IValidatableObject
    {
        public int Id { get; set; }
        [Required]
        public string Title { get; set; }
        public string BloggerName { get; set; }
        public DateTime DateCreated { get; set; }
        public virtual ICollection<Post> Posts { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Title == BloggerName)
            {
                yield return new ValidationResult
                 ("Blog Title cannot match Blogger Name", new[] { "Title", “BloggerName” });
            }
        }
    }

Entity Framework Validation

Upvotes: 0

Related Questions