0

I have a list of checkboxes that a user can select. I am saving the list using Entity Framework Code First. These are my models:

public class Company {
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Type> Types { get; set; }
}

public class Type {
    public int ID { get; set; }
    public string Name { get; set; }
}

A company has a list of types that belong to it. Some of these types depend on eachother. For example: my type with the name BMI depends on the types with the names length and weight. To enforce this I am currently using jQuery but I would like to handle it in the model. I am thinking about something like this:

[Dependency("BMI", DependsOn = { "length", "weight" })]

Is there a way to enforce dependencies within a list using Data Annotations? If there's not: what would be the best way to enforce these dependencies without having to use jQuery?

Attempt one

So, I started working on a solution. Here's my code so far:

class TypeDependencyAttribute : ValidationAttribute
{
    public string Dependant { get; set; }
    public string[] Dependencies { get; set; }

    public TypeDependencyAttribute(string dependant, string[] dependencies)
    {
        Dependant = dependant;
        Dependencies = dependencies;
    }

    public override bool IsValid(object value)
    {
        List<Isala.Models.Metingen.Type> list = value as List<Isala.Models.Metingen.Type>;
        if (list.Any(p => p.Naam == Dependant))
        {
            foreach(var dependency in Dependencies){
                if (!list.Any(p => p.Naam == dependency))
                {
                    return false;
                }
            }
        }
        return true;
    }
}

And in my model:

[TypeDependency("BMI", new string {"Lengte", "Gewicht"})]
[DataMember(IsRequired = true)]
public ICollection<Type> Types { get; set; }

This brings me to my next problem. According to this answer on another question you can't pass an array to an validation attribute. This renders my solution quite useless.

Attempt two

Next try, let's loose the array and do it like this:

[TypeDependency("BMI", "Lengte")]
[TypeDependency("BMI", "Gewicht")]
[DataMember(IsRequired = true)]
public ICollection<Type> Types { get; set; }

Well, you can't, according to this errormessage:

"Duplicate 'TypeDependency' attribute"

Appearently, the compiler doesn't like this either. Now, there ís another solution I can think of, but I don't like it:

[TypeDependent]
[DataMember(IsRequired = true)]
public ICollection<Type> Types { get; set; }

Attribute:

class TypeDependencyAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        List<Isala.Models.Metingen.Type> list = value as List<Isala.Models.Metingen.Type>;
        if (list.Any(p => p.Naam == "BMI"))
        {
            if (!list.Any(p => p.Naam == "Lengte") && !list.Any(p => p.Naam == "Gewicht"))
            {
                return false;
            }
        }
        return true;
    }
}

Is this my only option? Can I work around this duplicate attribute error (I need multiple dependencies, BMI isn't the only one).

Community
  • 1
  • 1
Scuba Kay
  • 2,004
  • 3
  • 26
  • 48

1 Answers1

1

you can create a custom data annotation for you custom needs

here is are some example

http://odetocode.com/Blogs/scott/archive/2011/02/21/custom-data-annotation-validator-part-i-server-code.aspx

How to create Custom Data Annotation Validators

Community
  • 1
  • 1
Anto Subash
  • 3,140
  • 2
  • 22
  • 30
  • I tried this, but it seems it's impossible to pass an array to an attribute. Please see my question for an update. – Scuba Kay Dec 17 '13 at 10:57
  • you cannot pass an array but you can pass multiple values. like `[Dependency("BMI","length", "weight")]` – Anto Subash Dec 17 '13 at 11:32
  • inserted of overriding `public override bool IsValid(object value)` try to override `protected override ValidationResult IsValid(object value, ValidationContext validationContext)`. bcos this has the validation context using which you can retrieve the passed values. – Anto Subash Dec 17 '13 at 11:38