You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:00:38