FluentValidation 中某属性值变更时如何触发所有关联属性的校验
问题根因
默认情况下FluentValidation执行属性级校验时,只会运行当前修改属性对应的校验规则,你修改了最早配送日期时,只会触发最早配送日期的规则校验,最晚配送日期的历史错误不会被自动清空,就会出现你遇到的问题。
解决方案
方案1:调整校验规则配置(推荐,无需修改UI层代码)
只要你用的是FluentValidation 11及以上版本,直接给两个关联规则加上WhenAny方法,指定两个属性任意一个变更时都触发两个规则的校验即可:
public class SomeValidator : AbstractValidator<SomeClass> { public SomeValidator () { RuleFor(x => x.EarliestDeliveryDate) .Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate) .WithMessage("最早配送日期必须早于最晚配送日期") // 指定最早/最晚配送日期任意一个变更,都触发当前规则校验 .WhenAny(x => x.EarliestDeliveryDate, x => x.LatestDeliveryDate); RuleFor(x => x.LatestDeliveryDate) .Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate) .WithMessage("最晚配送日期必须晚于最早配送日期") // 指定最早/最晚配送日期任意一个变更,都触发当前规则校验 .WhenAny(x => x.EarliestDeliveryDate, x => x.LatestDeliveryDate); } }
方案2:UI层手动触发关联校验
如果你用的FluentValidation版本较低不支持WhenAny,可以在UI的属性变更回调里手动触发关联属性的校验:
举Blazor EditContext场景的示例:
private EditContext _editContext; private SomeClass _model = new SomeClass(); protected override void OnInitialized() { _editContext = new EditContext(_model); // 监听字段变更事件 _editContext.OnFieldChanged += (sender, e) => { // 如果变更的是两个关联属性之一 if (e.FieldIdentifier.FieldName is nameof(SomeClass.EarliestDeliveryDate) or nameof(SomeClass.LatestDeliveryDate)) { // 手动通知两个属性都发生了变更,触发对应校验 _editContext.NotifyFieldChanged(FieldIdentifier.Create(() => _model.EarliestDeliveryDate)); _editContext.NotifyFieldChanged(FieldIdentifier.Create(() => _model.LatestDeliveryDate)); } }; }
如果是WPF/MAUI等MVVM架构的场景,直接在属性的set方法中触发关联属性的变更通知即可:
private DateTime _earliestDeliveryDate; public DateTime EarliestDeliveryDate { get => _earliestDeliveryDate; set { // 你的基础赋值逻辑,比如SetProperty _earliestDeliveryDate = value; OnPropertyChanged(nameof(EarliestDeliveryDate)); // 触发关联属性的变更通知,连带触发校验 OnPropertyChanged(nameof(LatestDeliveryDate)); } } private DateTime _latestDeliveryDate; public DateTime LatestDeliveryDate { get => _latestDeliveryDate; set { _latestDeliveryDate = value; OnPropertyChanged(nameof(LatestDeliveryDate)); OnPropertyChanged(nameof(EarliestDeliveryDate)); } }
方案3:合并为模型级校验
如果不需要单独给两个属性加错误提示,可以直接把规则合并为模型级规则,任意属性变更都会触发整个模型的校验:
RuleFor(x => x) .Must(x => x.EarliestDeliveryDate < x.LatestDeliveryDate) .WithMessage("最早配送日期必须早于最晚配送日期");
内容的提问来源于stack exchange,提问作者SuperUser
相关产品推荐
相关产品推荐

