【问题标题】:FluentValidation to find overlaping datetimes within a listFluentValidation 在列表中查找重叠的日期时间
【发布时间】:2020-02-25 22:19:48
【问题描述】:

我想知道是否有人可以帮助我,因为我只是在学习。我正在尝试使用 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.");
    }
}

【问题讨论】:

    标签: c# asp.net-mvc .net-core fluentvalidation


    【解决方案1】:

    有几种方法可以做到。

    首先,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.");
            }
        }
    });
    

    如果您一遍又一遍地进行相同类型的检查,您可以将检查的内容移到另一种方法中以使测试更易于阅读,或者使用可重用的属性验证器来进一步了解它。我不打算在这里介绍它们,因为这不是所要求的,但是它们已在上面的链接中介绍。

    上述规则的一个工作示例可以在here找到。

    此外,我会考虑将 start 属性的房间计划验证器更改为 NotEqual,因为看起来您想在 start 等于 end 时触发该验证错误; Equal 扩展只会在它们不相等时触发验证消息。这就像一个断言,如果它们相等则一切正常,否则返回验证错误。 Equal 扩展的 Doco:

    /// <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 结束 == 1pm && 时间表 2 开始 == 1pm 不是重叠。将比较更改为使用 = 以完全不允许重叠。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-15
      • 2018-08-29
      • 1970-01-01
      • 1970-01-01
      • 2019-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多