Проверка дочерней модели с использованием значений родительской модели. Беглое Подтверждение. MVC4 с
Ниже приведена упрощенная версия моей проблемы.
Я не могу расплющить модель. Есть список "детей", которые мне нужны для подтверждения дня рождения.
Я не могу, кажется, ссылаться на дату в родительском классе и было интересно, как это делается в Fluent Validation?
Модель
[Validator(typeof(ParentValidator))]
public class Parent
{
public string Name { get; set; }
public DateTime Birthdate { get; set; }
public List<Child> Children { get; set; }
}
public class Child
{
public string ChildProperty{ get; set; }
public DateTime Birthdate { get; set; }
}
Валидатор
public class ParentValidator : AbstractValidator<Parent>
{
public ParentValidator()
{
RuleFor(model => model.Name).NotEmpty();
RuleForEach(model => model.Children).SetValidator(new ChildValidator());
}
}
public class ChildValidator : AbstractValidator<Child>
{
public ChildValidator()
{
RuleFor(model => model.ChildProperty).NotEmpty();
//Compare birthday to make sure date is < Parents birthday
}
}
3 ответа:
Создайте пользовательский валидатор свойств, как это
public class AllChildBirtdaysMustBeLaterThanParent : PropertyValidator { public AllChildBirtdaysMustBeLaterThanParent() : base("Property {PropertyName} contains children born before their parent!") { } protected override bool IsValid(PropertyValidatorContext context) { var parent = context.ParentContext.InstanceToValidate as Parent; var list = context.PropertyValue as IList<Child>; if (list != null) { return ! (list.Any(c => parent.BirthDay > c.BirthDay)); } return true; } }
Добавьте такие правила
public class ParentValidator : AbstractValidator<Parent> { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Children) .SetValidator(new AllChildBirtdaysMustBeLaterThanParent()); // Collection validator RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator()); } }
Альтернативой валидатору пользовательских свойств является использование пользовательского метода:
public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator()); Custom(parent => { if (parent.Children == null) return null; return parent.Children.Any(c => parent.BirthDay > c.BirthDay) ? new ValidationFailure("Children", "Child cannot be older than parent.") : null; }); }
Грубый способ отображения индексов, которые потерпели неудачу: (вероятно, должно быть имя какого-то другого идентификатора)
public class ParentValidator : AbstractValidator<Parent> { public ParentValidator() { RuleFor(m => m.Children).SetCollectionValidator(new ChildValidator()); Custom(parent => { if (parent.Children == null) return null; var failIdx = parent.Children.Where(c => parent.BirthDay > c.BirthDay).Select(c => parent.Children.IndexOf(c)); var failList = string.Join(",", failIdx); return failIdx.Count() > 0 ? new ValidationFailure("Children", "Child cannot be older than parent. Fail on indicies " + failList) : null; }); } }
Есть более простой способ сделать это с помощью set child validator:
public class ChildValidator : AbstractValidator<Child> { public ChildValidator(Parent parent) { RuleFor(model => model.ChildProperty).NotEmpty(); RuleFor(model => model.Birthday).Must(birthday => parent.Birthday > birthday); } } public class ParentValidator : AbstractValidator<Parent> { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); } public override ValidationResult Validate(Parent parent) { RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator(this)); return base.Validate(); } }
В настоящее время ответ на вопрос @johnny-5 можно упростить еще больше, используя метод расширения
SetCollectionValidator
и передавая родительский объект дочернему валидатору:public class ParentValidator : AbstractValidator<Parent> { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Children) .SetCollectionValidator(model => new ChildValidator(model)) } } public class ChildValidator : AbstractValidator<Child> { public ChildValidator(Parent parent) { RuleFor(model => model.ChildProperty).NotEmpty(); RuleFor(model => model.Birthday).Must(birthday => parent.Birthday < birthday); } }