简体   繁体   English

FluentValidation 比较来自不同类的 2 个值

[英]FluentValidation compare 2 values from different classes

I have 2 classes in model and I would like to validate that value in a field from one class is smaller than field from second class.我在模型中有 2 个类,我想验证一个类的字段中的值小于第二个类的字段。 I went through Fluent documentation but I cannot find a real example.我浏览了 Fluent 文档,但找不到真实示例。

public class inputModel
{
    public double Iy { get; set; }
    public bool selfWeight { get; set; }
    public double span { get; set; }
    public string spanType { get; set; }
}

public class pointLoad
{
    public double pLoad { get; set; }
    public double pDist { get; set; }
}

I need to validate that field pDist cannot be greater than span.我需要验证字段 pDist 不能大于跨度。

public class pointLoadFluentValidator : AbstractValidator<pointLoad>
{
    public pointLoadFluentValidator()
    {
        RuleFor(x => x.pLoad)
            .NotEmpty()
            .NotNull()
            .LessThan(9999);

        RuleFor(x => x.pDist)
            .NotEmpty()
            .NotNull()
            .LessThan(99);

    }

Thanks.谢谢。

Assuming that you're using the latest version of FV, and there is no way to establish a relationship between the models, I'd normally tackle this using RootDataContext .假设您使用的是最新版本的 FV,并且无法在模型之间建立关系,我通常会使用RootDataContext来解决这个问题 You haven't stated how you're invoking your validators, however this method becomes a server side invocation - you'll need to invoke the validator manually as you need to populate the root data context dictionary.您尚未说明如何调用验证器,但是此方法成为服务器端调用 - 您需要手动调用验证器,因为您需要填充根数据上下文字典。

Provided the above suits, then start by adding a rule:提供以上花色,然后开始添加规则:

RuleFor(x => x.pDist).Must((pointLoad, pDist, validationContext) =>
{
    if (!validationContext.RootContextData.ContainsKey("inputModelToCompareAgainst"))
    {
        return true;
    }

    var inputModel = (inputModel)validationContext.RootContextData["inputModelToCompareAgainst"];
    return pDist <= inputModel.span;
})
.WithMessage("My error message");

Then invoke the validator with a validation context:然后使用验证上下文调用验证器:

var validator = new pointLoadFluentValidator();
var validationContext = new ValidationContext<pointLoad>(pointLoad);
validationContext.RootContextData["inputModelToCompareAgainst"] = inputModel;
var validationResult = validator.Validate(validationContext);

Working LINQPad example (with examples for Custom and Must validators):工作 LINQPad 示例(包含CustomMust验证器的示例):

void Main()
{
    var fixture = new Fixture();
    var pointLoad = fixture.Build<pointLoad>().With(x => x.pLoad, 10).With(x => x.pDist, 20).Create();
    var inputModel = fixture.Build<inputModel>().With(x => x.span, pointLoad.pDist - 1).Create();

    var validator = new pointLoadFluentValidator();
    var validationContext = new ValidationContext<pointLoad>(pointLoad);
    validationContext.RootContextData["inputModelToCompareAgainst"] = inputModel;
    var validationResult = validator.Validate(validationContext);

    validationResult.Errors.Select(x => x.ErrorMessage).Should().BeEquivalentTo(new[] { "My error message" });
}

// You can define other methods, fields, classes and namespaces here
public class inputModel
{
    public double Iy { get; set; }
    public bool selfWeight { get; set; }
    public double span { get; set; }
    public string spanType { get; set; }
}

public class pointLoad
{
    public double pLoad { get; set; }
    public double pDist { get; set; }
}

public class pointLoadFluentValidator : AbstractValidator<pointLoad>
{
    public pointLoadFluentValidator()
    {
        RuleFor(x => x.pLoad)
            .NotEmpty()
            .NotNull()
            .LessThan(9999);

        RuleFor(x => x.pDist)
            .NotEmpty()
            .NotNull()
            .LessThan(99);

        //pointLoad.pDist cannot be greater than inputModel.span, therefore pointLoad.pDist must be less than or equal to inputModel.span

        //RuleFor(x => x.pDist).Custom((pDist, validationContext) =>
        //{
        //  if (validationContext.RootContextData.ContainsKey("inputModelToCompareAgainst"))
        //  {
        //      var inputModel = (inputModel)validationContext.RootContextData["inputModelToCompareAgainst"];
        //      if (pDist > inputModel.span)
        //          validationContext.AddFailure("My error message");
        //  }
        //});

        RuleFor(x => x.pDist).Must((pointLoad, pDist, validationContext) =>
        {
            if (!validationContext.RootContextData.ContainsKey("inputModelToCompareAgainst"))
            {
                return true;
            }

            var inputModel = (inputModel)validationContext.RootContextData["inputModelToCompareAgainst"];
            return pDist <= inputModel.span;
        })
        .WithMessage("My error message");
    }
}

If you are relying on the HTTP request pipeline middleware to invoke the validator, then we need more information.如果您依赖 HTTP 请求管道中间件来调用验证器,那么我们需要更多信息。 It sounds like inputModel is the user input.听起来 inputModel 是用户输入。 Is pointLoad input as well? pointLoad 也是输入吗? Is it data from a repository?它是来自存储库的数据吗? There may be other options (eg, perform this validation rule in an inputModel validator, which takes a pointLoad repository as constructor; the validation is still server side, but can be done automatically in the middleware).可能还有其他选项(例如,在 inputModel 验证器中执行此验证规则,它将 pointLoad 存储库作为构造函数;验证仍然是服务器端,但可以在中间件中自动完成)。

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

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