FluentValidation, чтобы найти перекрывающиеся даты и времени в списке - PullRequest
0 голосов
/ 26 февраля 2020

Мне интересно, может ли кто-нибудь мне помочь, потому что я только учусь. Я пытаюсь использовать FluentValidation для проверки списка дат, чтобы улучшить свои навыки, но я не могу решить проблему и могу найти пример того, что я пытаюсь сделать. По сути, я хочу сделать следующее:

  1. Проверьте, не начинается ли начало раньше конца (Хорошо)
  2. Проверьте, не совпадают ли время начала и время (Хорошо )
  3. Проверьте, нет ли перекрывающегося начала и заканчивается в тот же день. (Не могу сделать)

Буду благодарен, если кто-нибудь сможет мне помочь. Код ниже

public class Room
{
    public DateTime RoomBooked { get; set; }

    public List<RoomSchedule> Schedule { get; set; }
}


public class RoomSchedule
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}


public class RoomValidator : AbstractValidator<Room>
{
    public RoomValidator()
    {
        RuleFor(o => o.RoomBooked)
                .NotEmpty().WithMessage("Booking can not be empty");

        RuleForEach(x => x.Schedule)
                .SetValidator(new RoomScheduleValidator());
    }
}


public class RoomScheduleValidator : AbstractValidator<RoomSchedule>
{
    public RoomScheduleValidator()
    {
        RuleFor(o => o.Start)
            .NotEmpty().WithMessage("Start time required.")
            .Equal(m => m.End).WithMessage("Start time can not be the same as the end time.");

        RuleFor(m => m.End)
            .NotEmpty().WithMessage("End time required.")
            .GreaterThan(m => m.Start)
            .WithMessage("End time can not be before start time.");
    }
}

1 Ответ

1 голос
/ 01 марта 2020

Есть несколько способов сделать это.

Во-первых, FV doco предлагает начать с расширения Must, чтобы делать подобные вещи. Для вашего случая вы бы сделали что-то подобное для вашего RoomValidator

RuleFor(o => o.Schedule).Must(schedule =>
    {
        if (schedule == null || !schedule.Any())
        {
            return true;
        }

        return schedule.All(item => !schedule.Where(x => !ReferenceEquals(item, x)).Any(x => x.Start < item.End && x.End > item.Start));
    })
    .WithMessage("Schedule can not have overlapping times.");

. Это выдаст вам одно сообщение об ошибке, если в списке расписания комнат будут совпадения даты и времени.

Если вы хотите больше контроля над сообщениями об ошибках; скажем, вы хотите распечатать, какие расписания перекрывались, используйте расширение Custom.

RuleFor(o => o.Schedule).Custom((schedule, context) =>
{
    if (schedule == null || !schedule.Any())
    {
        return;
    }

    foreach (var item in schedule)
    {
        var scheduleOverlapsAnotherSchedule = schedule.Where(x => !ReferenceEquals(item, x)).Any(x => x.Start < item.End && x.End > item.Start);
        if (scheduleOverlapsAnotherSchedule)
        {
            context.AddFailure($"Schedule {item.Start.ToShortTimeString()}-{item.End.ToShortTimeString()} overlaps another schedule.");
        }
    }
});

Вы можете пойти дальше, переместив кишки чека в другой метод, чтобы упростить тест. читать или повторно использовать валидатор свойства, если вы делаете один и тот же вид проверки снова и снова. Я не буду описывать их здесь, так как это не то, о чем просили, однако они описаны в приведенной выше ссылке.

Рабочий пример вышеуказанных правил можно найти здесь .

Кроме того, я хотел бы рассмотреть возможность изменения вашего валидатора расписания комнат для свойства start на NotEqual, так как похоже, что вы хотите вызвать эту ошибку проверки, когда start равно end; расширение Equal вызовет сообщение проверки, только если они не равны. Это как утверждение, если они равны, все хорошо, в противном случае возвращает ошибку проверки. Документ для расширения Equal:

/// <summary>
/// Defines an 'equals' validator on the current rule builder using a lambda to specify the comparison value.
/// Validation will fail if the value returned by the lambda is not equal to the value of the property.
/// </summary>

РЕДАКТИРОВАТЬ: Для проверки перекрытия я предположил, что время начала и окончания между расписаниями может быть одинаковым, например, конец 1 расписания == 13:00 && запуск расписания 2 2 == 13:00 не являются совпадением. Измените сравнение, чтобы использовать <= и> =, чтобы вообще не перекрывать.

...