Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Complex Type Custom Validation, Stopping Validation Recursion

We are using complex types to manage our translatable fields like this:

[ComplexType]
public class Translated
{
    [Required]
    public string NL { get; set; }

    [Required]
    public string EN { get; set; }

    [ScaffoldColumn(false)]
    public string TranslatedText
    {
        get
        {
           return Util.Translate(NL, EN); 
        }
    }
}

We require the fields to be present. But in some cases the whole Translated field is optional as in:

public class Question
{
    ...

    [Optional(ErrorMessage="Foo")]
    public Translated Description { get; set; }

    ...
}

However, it seems that the Optional attribute gets calculated, and when it returns false nothing is done with the result.

class OptionalAttribute : ValidationAttribute 
{
    public override bool IsValid(object value)
    {
        return false;
    }
}

When I put the optional attribute on a non-complex type it works as expected, the error message will always be Foo.

The ultimate goal is to allow the Description to be empty in both cases, but when one of the fields is filled the errors should of course propagate.

Stopping the validation recursion would cause the field to be optional, but it would also prevent the validation of the fields in case they are filled in.

Any ideas on how to accomplish this?

like image 826
Alessandro Vermeulen Avatar asked Apr 12 '11 12:04

Alessandro Vermeulen


1 Answers

Using the data annotation [Required] on your string properties will create non nullable fields in the database. From your description it seems that sometimes you'll want both of those values to be null.

I would suggest implementing your own validation defining what makes those fields optional.

[ComplexType]
public class Translated : IValidatableObject
{
    public string NL { get; set; }

    public string EN { get; set; }

    [NotMapped]
    public string TranslatedText
    {
        get
        {
            return Util.Translate(NL, EN);
        }
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrEmpty(NL) && string.IsNullOrEmpty(EN))
            yield return new ValidationResult("EN is required if NL is entered.");

        if (!string.IsNullOrEmpty(EN) && string.IsNullOrEmpty(NL))
            yield return new ValidationResult("NL is required if EN is entered.");
    }
}
like image 92
ckal Avatar answered Oct 04 '22 15:10

ckal