【问题标题】:Trigger Validation of a related property (FluentValidation)触发相关属性的验证 (FluentValidation)
【发布时间】:2021-10-07 09:19:50
【问题描述】:

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

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)的错误消息仍然存在。

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

【问题讨论】:

  • 那么,LatestDeliveryDate 在这种情况下的日期无效?
  • @GregBurghardt 问题是,一旦用户更正了其中一个属性,这将使这两个属性都有效。但验证规则将仅针对修改后的属性进行评估,而为其他属性留下错误消息。如果其中一个发生更改,我想对这两个属性强制执行验证。

标签: c# fluentvalidation


【解决方案1】:

我的建议是让您的模型类实现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 之类的框架,当相关属性之一发生更改时,其他属性也会自动触发验证。但是,如果您的 UI 框架不刷新在引发NotifyPropertyChanged 时自动查看,您需要订阅该事件并让 UI 触发相关属性的验证。例如在 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>

【讨论】:

  • 您提出的解决方案完美地解决了我的问题。标记为已回答,谢谢!在本例中,UI 框架是 Blazor。
【解决方案2】:

DateTime 结构的默认值为公元 1 年 1 月 1 日。也许用户界面中的无效日期被回发,然后被忽略,因此使用 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.");
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2023-03-22
    • 2021-06-21
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多