触发相关 属性 的验证 (FluentValidation)

Trigger Validation of a related property (FluentValidation)

我在 class 中有两个相互依赖的属性:

public class SomeClass
{
  public DateTime EarliestDeliveryDate { get; set; }
  public DateTime LatestDeliveryDate { get; set; }
...
}

我将 FluentValidation 配置如下:

using FluentValidation;
...

    public class SomeValidator : AbstractValidator<SomeClass>
    {
        public SomeValidator ()
        {
            RuleFor(x => x.EarliestDeliveryDate).Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate)
                .WithMessage("Earliest delivery date has to be before the latest delivery date.");

            RuleFor(x => x.LatestDeliveryDate)
                .Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate)
                .WithMessage("Latest delivery date has to be after the earliest delivery date.");
...
        }
    }

每个 属性 的验证都按预期工作。但是,如果用户为两个属性输入了无效日期,然后更正其中一个输入字段(假设是 EarliestDeliveryDate),则另一个 属性(例如 LatestDeliveryDate)的错误消息仍然存在。

如果一个 属性 的值发生变化,如何触发所有依赖属性的验证?

DateTime 结构的默认值为 1 月 1 日 A.D。也许用户界面中的无效日期被回发,然后被忽略,因此使用 DateTime 的默认值。

要解决此问题,您需要通过在 属性 类型的名称后放置一个 ? 字符来使每个属性都可以为空:DateTime?

public class SomeClass
{
    public DateTime? EarliestDeliveryDate { get; set; }
    public DateTime? LatestDeliveryDate { get; set; }
    ...
}

那么无效日期将是 null,更糟糕的情况。如果两个日期都包含 DateTime 对象,您只想比较两个日期:

// If both fields are required:
RuleFor(x => x.EarliestDeliveryDate)
    .NotEmpty();

RuleFor(x => x.LatestDeliveryDate)
    .NotEmpty();

When(order => order.EarliestDeliveryDate.HasValue && order.LatestDeliveryDate.HasValue, () =>
{
    RuleFor(x => x.EarliestDeliveryDate)
        .Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate)
        .WithMessage("Earliest delivery date has to be before the latest delivery date.");

    RuleFor(x => x.LatestDeliveryDate)
        .Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate)
        .WithMessage("Latest delivery date has to be after the earliest delivery date.");
});

我的建议是让您建模 class 实现 INotifyPropertyChanged 接口,然后在所有相关属性的 Setter 中引发事件,如下所示:

public int LocationId
{
    get => locationId;
    set
    {
        locationId = value;
        NotifyPropertyChanged(nameof(LocationId));
        if (HazardId != default && MeasuredPersianDate != default)
        {
            NotifyPropertyChanged(nameof(HazardId));
            NotifyPropertyChanged(nameof(MeasuredPersianDate));
        }
    }
}

这样,如果你的 UI 是像 WPF 或 Xamarin Forms 这样的框架,当其中一个相关属性发生变化时,其他属性也会被触发验证 automatically.However,如果当 NotifyPropertyChanged 出现时,您的 UI 框架不会自动刷新视图,您需要订阅该事件并让 UI 触发相关 properties.For 的验证在 Blazor 中的示例,您可以使用以下代码:

model.PropertyChanged +=
    (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
    {
        if (e.PropertyName is null) return;
        form.EditContext!.NotifyFieldChanged(form.EditContext.Field(e.PropertyName));
    };

其中 form 是使用 @ref

引用 EditForm 的变量
<EditForm @ref="form" Context="ctx" Model="model"OnValidSubmit="SaveChanges">...</EditForm>