FluentValidation 在列表中查找重叠的日期时间
FluentValidation to find overlaping datetimes within a list
我想知道是否有人可以帮助我,因为我只是在学习。我正在尝试使用 FluentValidation 来验证日期时间列表,以提高我的技能,但我似乎无法解决问题,而且我似乎可以找到我正在尝试做的事情的例子。基本上,我想做的是:
- 检查开始是否在结束之前(好的)
- 检查开始时间和时间是否不相等(好)
- 检查在同一天没有重叠的开始和结束。 (做不到)
如果有人能帮助我,我将不胜感激。下面的代码
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.");
}
}
有几种方法可以做到这一点。
首先,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.");
}
}
});
您可以通过将检查的核心转移到另一种方法中使测试更易于阅读,或者如果您一遍又一遍地进行相同类型的检查,则可以使用可重用的 属性 验证器来进一步改进.我不打算在这里介绍它们,因为这不是所要求的,但是它们在上面 link.
可以找到上述规则的工作示例 here。
此外,我会考虑将您的房间时间表验证器从开始 属性 更改为 NotEqual
,因为看起来您希望在开始等于结束时触发该验证错误; Equal
扩展只会在它们不相等时触发验证消息。这就像一个断言,如果它们相等则一切正常,否则 return 验证错误。 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 结束 == 下午 1 点 && 时间表 2 开始 == 下午 1 点不是重叠。将比较更改为使用 <= 和 >= 以完全不允许重叠。
我想知道是否有人可以帮助我,因为我只是在学习。我正在尝试使用 FluentValidation 来验证日期时间列表,以提高我的技能,但我似乎无法解决问题,而且我似乎可以找到我正在尝试做的事情的例子。基本上,我想做的是:
- 检查开始是否在结束之前(好的)
- 检查开始时间和时间是否不相等(好)
- 检查在同一天没有重叠的开始和结束。 (做不到)
如果有人能帮助我,我将不胜感激。下面的代码
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.");
}
}
有几种方法可以做到这一点。
首先,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.");
}
}
});
您可以通过将检查的核心转移到另一种方法中使测试更易于阅读,或者如果您一遍又一遍地进行相同类型的检查,则可以使用可重用的 属性 验证器来进一步改进.我不打算在这里介绍它们,因为这不是所要求的,但是它们在上面 link.
可以找到上述规则的工作示例 here。
此外,我会考虑将您的房间时间表验证器从开始 属性 更改为 NotEqual
,因为看起来您希望在开始等于结束时触发该验证错误; Equal
扩展只会在它们不相等时触发验证消息。这就像一个断言,如果它们相等则一切正常,否则 return 验证错误。 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 结束 == 下午 1 点 && 时间表 2 开始 == 下午 1 点不是重叠。将比较更改为使用 <= 和 >= 以完全不允许重叠。