简体   繁体   English

FluentValidation:在子集合规则中使用父属性值

[英]FluentValidation: Using a parent property value in a child collection rule

I have this validator:我有这个验证器:

 public class InputValidator : AbstractValidator<InputData>
{
    public InputValidator()
    { 
        RuleFor(inputData => inputData.Ucl).GreaterThan(0).....;

        RuleForEach(inputData => inputData.Loads).ChildRules(inputData => {            
              inputData.RuleFor(load => load.Position).GreaterThan(0).....); 
            });
... etc

However: Position (in each load) must also be less than Ucl (in InputData).但是:Position(在每次加载中)也必须小于 Ucl(在 InputData 中)。 How can I make a rule for such a relation (parent parameter vs. child parameter)?我如何为这种关系制定规则(父参数与子参数)?

I don't think there is a nice way to do it inline.我认为没有一种很好的内联方式。 Child rules doesn't allow you to pass in the parent object.子规则不允许您传入父 object。 Must and I think Custom (via context.ParentContext.InstanceToValidate maybe) would allow you to add rules(s) involving both the parent and child but the rule(s) would be against the collection rather than each item. Must并且我认为Custom (可能通过context.ParentContext.InstanceToValidate )将允许您添加涉及父项和子项的规则,但规则将针对集合而不是每个项目。 The better way, and how I'd normally do it would be to create a child validator for your Load entity:更好的方法,以及我通常的做法是为您的Load实体创建一个子验证器:

public class LoadValidator : AbstractValidator<Load>
{
    public LoadValidator(InputData inputData)
    {
        RuleFor(load => load.Position)
                .GreaterThan(0).WithMessage("Position must be greater than 0")
                .LessThan(inputData.Ucl).WithMessage("Position must be less than Ucl");     
    }
}

This becomes reusable and a lot easier to test.这变得可重用并且更容易测试。 Then use SetValidator to use it.然后使用SetValidator来使用它。

public class InputDataValidator : AbstractValidator<InputData>
{
    public InputDataValidator()
    {
        RuleFor(inputData => inputData.Ucl)
            .GreaterThan(0).WithMessage("Ucl must be greater than 0");

        RuleForEach(inputData => inputData.Loads)
            .SetValidator(inputData => new LoadValidator(inputData));
    }
}

Reusable property validators could be another way of doing it, but for me it'd have to be a reasonably high level/generic case to bother with implementing one. 可重用的属性验证器可能是另一种实现方式,但对我来说,它必须是一个相当高级/通用的案例才能实现一个。

By using Root Context Data , it's also possible to set any arbitrary object on the parent context during pre-validation.通过使用根上下文数据,还可以在预验证期间在父上下文中设置任意 object。 You could then access this object through the context parameter during evaluation of a custom rule.然后,您可以在评估自定义规则期间通过上下文参数访问此 object。

A simple example would look something like:一个简单的例子看起来像:

public class InputValidator : AbstractValidator<InputData>
{
  protected override bool PreValidate(ValidationContext<InputData> context, ValidationResult result)
  {
    //RootContextData is a Dictionary<string, object> which can have any arbitrary objects added in during prevalidation
    context.RootContextData["InputDataBeingValidated"] = context.InstanceToValidate;

    return base.PreValidate(context, result);
  }

  public InputValidator()
  { 
      RuleFor(inputData => inputData.Ucl).GreaterThan(0); //....

      RuleForEach(inputData => inputData.Loads).ChildRules(inputData => {            
            inputData.RuleFor(load => load.Position).GreaterThan(0)
              .Custom((pos, ctx) =>
                {
                  var currentInstance = ctx.ParentContext.RootContextData["InputDataBeingValidated"];
                  if(pos >= currentInstance.Ucl)
                  {
                    ctx.AddFailure("Build your error message here");
                  }
                }
              );
            ); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM