Использование FluentValidation для проверки взаимоисключающих полей

Я пытаюсь проверить, что только одно из трех полей имеет значение, используя FluentValidation.

RuleFor(x => x.Date1)
            .Must(x => !x.HasValue)
            .When(x => x.Date2.HasValue || x.Date3.HasValue)
            .WithMessage("Select only one of Date 1, Date 2 and Date 3");

Это повторяется для двух других дат. Как и следовало ожидать, это создает сообщение для каждого правила, которое соответствует.

Есть и другие правила, поэтому есть ли способ выполнить другие правила, но не выполнить первое из этих трех? Я видел, где можно глобально установить CascadeMode.StopOnFirstFailure, но я хочу, чтобы другие правила, кроме этих трех, работали так, как они работают сейчас.


person dalevross    schedule 31.03.2015    source источник
comment
Объедините три правила в одно правило .Custom(...).   -  person Maarten    schedule 31.03.2015


Ответы (3)


Я решаю пойти другим путем. Это выглядит элегантно, но я узнаю, пройдет ли проверка кода.

Я создал новое свойство

    public IEnumerable<DateTime?> MutuallyExclusiveDates
    {
        get
        {
            return new List<DateTime?>()
            {
                Date1,
                Date2,
                Date3
            };

        }
    }

Затем я добавил это правило

 RuleFor(x => x.MutuallyExclusiveDates)
            .Must(x => x.Count(d => d.HasValue) <= 1)
            .WithMessage("Select only one of Date 1, Date 2 and Date 3");
person dalevross    schedule 31.03.2015
comment
Разве вы не можете заменить лямбду, выбирающую значение свойства в вызове RuleFor(...), на лямбду, возвращающую список, содержащий три даты? Затем вы можете удалить лишнее свойство. - person Maarten; 01.04.2015
comment
Вчера был мой первый опыт использования FluentValidation, поэтому после нескольких неудачных попыток этот сработал. Мне нравится тот факт, что модель может быть легко обновлена ​​с учетом соответствующих дат. - person dalevross; 01.04.2015

Простое одно правило для всех 3 с использованием xor. Никаких дополнительных свойств не требуется. выньте, если вы хотите, чтобы хотя бы один имел значение.

 RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure)
     .Must(x => (x.date1.HasValue ^ x.date2.HasValue) ^ x.date3.HasValue)
     .Unless(x => !x.date1.HasValue && !x.date2.HasValue && !x.date3.HasValue)
     .WithMessage("Select only one of Date 1, Date 2 and Date 3");
person Daniel Davis    schedule 15.03.2019

я бы использовал что-то вроде

RuleFor(x => x).Must(ValidateDates).WithName("something");

<snip/>

private bool ValidateDates(SomeRequest request)
{
   //perform logic and return true/false;
}

Внутри метода ValidateDates у вас есть доступ к полному запросу.

Дополнительные примеры сложной проверки с использованием Must можно найти в этом сообщении — http://nodogmablog.bryanhogan.net/2015/04/complex-model-validation-using-fluent-validation/

person Bryan    schedule 12.04.2015