如何用Fluent Validation实现两个Trip列表的TravelDate比较验证?
解决方案
根据你的类结构和验证需求,这里提供两种场景的Fluent Validation实现:
场景1:OutTripDetails和InTripDetails是单个Trip(匹配原始验证逻辑)
如果你的BookingDto中OutTripDetails和InTripDetails实际应为单个Trip而非集合(对应你给出的原始if逻辑),可以直接通过属性关联验证实现:
修正后的类定义
public class BookingDto { public Trip OutTripDetails { get; set; } public Trip InTripDetails { get; set; } } public class Trip { public DateTime? TravelDate { get; set; } public IEnumerable<ClassTst> Stops { get; set; } }
验证器实现
public class BookingDtoValidator : AbstractValidator<BookingDto> { public BookingDtoValidator() { RuleFor(dto => dto.InTripDetails.TravelDate) // 确保返程日期不早于去程日期 .GreaterThanOrEqualTo(dto => dto.OutTripDetails.TravelDate) // 仅当两个Trip都存在且TravelDate不为null时触发验证 .When(dto => dto.OutTripDetails != null && dto.InTripDetails != null && dto.OutTripDetails.TravelDate.HasValue && dto.InTripDetails.TravelDate.HasValue) .WithMessage("返程出发日期不能早于去程出发日期"); } }
场景2:OutTripDetails和InTripDetails是Trip集合
如果确实需要处理集合类型的Trip,需要针对整个BookingDto对象编写自定义验证逻辑,因为要跨两个集合进行关联校验:
验证器实现
public class BookingDtoValidator : AbstractValidator<BookingDto> { public BookingDtoValidator() { RuleFor(dto => dto) .Must(MeetTravelDateRequirements) .WithMessage("存在返程出发日期早于去程出发日期的情况"); } private bool MeetTravelDateRequirements(BookingDto dto) { // 处理集合为空的情况,可根据业务需求调整(比如要求必须有Trip则返回false) if (dto.OutTripDetails == null || !dto.OutTripDetails.Any() || dto.InTripDetails == null || !dto.InTripDetails.Any()) { return true; } // 按索引对应比较去程和返程的Trip(第一个去程对应第一个返程) var outTrips = dto.OutTripDetails.ToList(); var inTrips = dto.InTripDetails.ToList(); for (int i = 0; i < Math.Min(outTrips.Count, inTrips.Count); i++) { var outDate = outTrips[i].TravelDate; var inDate = inTrips[i].TravelDate; if (outDate.HasValue && inDate.HasValue && inDate.Value < outDate.Value) { return false; } } return true; } }
自定义逻辑调整
如果你的需求是所有返程Trip的日期都不能早于任何去程Trip的日期,可以修改MeetTravelDateRequirements方法:
private bool MeetTravelDateRequirements(BookingDto dto) { if (dto.OutTripDetails == null || !dto.OutTripDetails.Any() || dto.InTripDetails == null || !dto.InTripDetails.Any()) { return true; } // 获取所有非空的去程日期,取最早的那个 var validOutDates = dto.OutTripDetails .Where(t => t.TravelDate.HasValue) .Select(t => t.TravelDate.Value) .ToList(); if (!validOutDates.Any()) { return true; } var earliestOutDate = validOutDates.Min(); // 验证所有非空的返程日期都不早于最早的去程日期 return dto.InTripDetails .Where(t => t.TravelDate.HasValue) .All(t => t.TravelDate.Value >= earliestOutDate); }
为什么RuleForEach不适用?
RuleForEach仅用于对集合内的每个元素进行独立属性验证,无法直接关联另一个集合的元素进行校验。而你的需求需要跨两个属性/集合做关联判断,因此需要使用针对整个对象的Must自定义验证,或者在When条件中同时校验多个关联属性的状态。
内容的提问来源于stack exchange,提问作者jubi
相关产品推荐
相关产品推荐

