【问题标题】:Child Model Validation using Parent Model Values. Fluent Validation. MVC4使用父模型值的子模型验证。流畅的验证。 MVC4
【发布时间】:2013-09-10 13:20:57
【问题描述】:

以下是我的问题的简化版本。

我无法展平模型。我需要一个“孩子”列表来验证生日。

我似乎无法在 Parent 类中引用日期,想知道在 Fluent Validation 中这是如何完成的?

型号

[Validator(typeof(ParentValidator))]
public class Parent
{
    public string Name { get; set; }
    public DateTime Birthdate { get; set; }

    public List<Child> Children { get; set; }
}

public class Child
{
    public string ChildProperty{ get; set; }
    public DateTime Birthdate { get; set; }
}

验证器

public class ParentValidator : AbstractValidator<Parent>
{
    public ParentValidator()
    {
         RuleFor(model => model.Name).NotEmpty();
         RuleForEach(model => model.Children).SetValidator(new ChildValidator());
    }
}

public class ChildValidator : AbstractValidator<Child>
{
    public ChildValidator()
    {
        RuleFor(model => model.ChildProperty).NotEmpty();
        //Compare birthday to make sure date is < Parents birthday
    }
}

【问题讨论】:

    标签: c# asp.net-mvc validation asp.net-mvc-4 fluentvalidation


    【解决方案1】:

    像这样创建一个自定义属性验证器

    public class AllChildBirtdaysMustBeLaterThanParent : PropertyValidator
    {
        public AllChildBirtdaysMustBeLaterThanParent()
            : base("Property {PropertyName} contains children born before their parent!")
        {
        }
    
        protected override bool IsValid(PropertyValidatorContext context)
        {
            var parent = context.ParentContext.InstanceToValidate as Parent;
            var list = context.PropertyValue as IList<Child>;
    
            if (list != null)
            {
                return ! (list.Any(c => parent.BirthDay > c.BirthDay));
            }
    
            return true;
        }
    }
    

    添加这样的规则

    public class ParentValidator : AbstractValidator<Parent>
    {
        public ParentValidator()
        {
            RuleFor(model => model.Name).NotEmpty();
            RuleFor(model => model.Children)
                   .SetValidator(new AllChildBirtdaysMustBeLaterThanParent());
    
            // Collection validator
            RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator());
        }
    }
    

    自定义属性验证器的替代方法是使用自定义方法:

        public ParentValidator()
        {
            RuleFor(model => model.Name).NotEmpty();
            RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator());
    
            Custom(parent =>
            {
                if (parent.Children == null)
                    return null;
    
                return parent.Children.Any(c => parent.BirthDay > c.BirthDay)
                   ? new ValidationFailure("Children", "Child cannot be older than parent.")
                   : null;
            });
        }
    

    显示失败指标的粗略方式:(应该是其他标识符的名称)

    public class ParentValidator : AbstractValidator<Parent>
    {
        public ParentValidator()
        {
            RuleFor(m => m.Children).SetCollectionValidator(new ChildValidator());
    
            Custom(parent =>
            {
                if (parent.Children == null)
                    return null;
    
                var failIdx = parent.Children.Where(c => parent.BirthDay > c.BirthDay).Select(c => parent.Children.IndexOf(c));
                var failList = string.Join(",", failIdx);
    
                return failIdx.Count() > 0
                   ? new ValidationFailure("Children", "Child cannot be older than parent. Fail on indicies " + failList)
                   : null;
            });
        }
    
    }
    

    【讨论】:

    • 我正在处理这个问题。目前我的问题是,当我进行此更改时,我的部分视图开始抱怨“没有为此对象定义无参数构造函数”。而且它在手前就开始工作了。
    • 其实我发现一个更简洁的错误是 RuleForEach(model => model.Children) .SetValidator(new ChildValidator(model));我无法在 .SetValidator 中传递模型。消息是“当前上下文中不存在名称“模型””
    • 据我所知,这是目前最干净的方法
    • 是否有另一种方法,因为这种方法甚至无法编译,因为模型在上下文中没有价值?
    • 用自定义方法方法的示例更新了我的答案,你会 +1 答案吗?
    【解决方案2】:

    编辑: SetCollectionValidator 已被弃用,但现在可以使用 RuleForEach 完成相同的操作:

    public class ParentValidator : AbstractValidator<Parent>
    {
        public ParentValidator()
        {
             this.RuleFor(model => model.Name).NotEmpty();
             this.RuleForEach(model => model.Children)
                    .SetValidator(model => new ChildValidator(model));
        }
    }
    
    public class ChildValidator : AbstractValidator<Child>
    {
        public ChildValidator(Parent parent)
        {
            this.RuleFor(model => model.ChildProperty).NotEmpty();
            this.RuleFor(model => model.Birthday).Must(birthday => parent.Birthday < birthday);
        }
    }
    

    【讨论】:

    • 你如何比较生日?我不明白你的答案?
    • 这个问题的重要部分是如何进行子验证。我不是在比较生日那条评论是为了让你在那里添加生日逻辑规则
    • 问题是关于如何将孩子的生日与父母的生日进行比较,从您的示例中不清楚如何实现,添加比较将使其成为更好的答案。引用:“我需要验证生日。” “我似乎无法在 Parent 类中引用日期,想知道在 Fluent Validation 中这是如何完成的?”
    • 你说得对,这里的东西看起来很奇怪,这个问题过去是否更新过给我一秒钟,我会更新这个
    • @TommyGrovnes Idk 那里发生了什么,但现在已修复
    【解决方案3】:

    现在@johnny-5 的answer 可以通过使用SetCollectionValidator 扩展方法并将父对象传递给子验证器来进一步简化:

    public class ParentValidator : AbstractValidator<Parent>
    {
        public ParentValidator()
        {
             RuleFor(model => model.Name).NotEmpty();
             RuleFor(model => model.Children)
                 .SetCollectionValidator(model => new ChildValidator(model))
        }
    }
    
    public class ChildValidator : AbstractValidator<Child>
    {
        public ChildValidator(Parent parent)
        {
            RuleFor(model => model.ChildProperty).NotEmpty();
            RuleFor(model => model.Birthday).Must(birthday => parent.Birthday < birthday);
        }
    }
    

    【讨论】:

    • @johnny 5 的回答将父 validator 传递给子验证器;你的将父 model 传递给子验证器。
    【解决方案4】:

    基于@kristoffer-jalen 的答案,现在是:

    public class ParentValidator : AbstractValidator<Parent>
    {
        public ParentValidator()
        {
             RuleFor(model => model.Name).NotEmpty();
             //RuleFor(model => model.Children)
             //    .SetCollectionValidator(model => new ChildValidator(model))
             RuleForEach(model => model.Children)
                    .SetValidator(model => new ChildValidator(model));
        }
    }
    
    public class ChildValidator : AbstractValidator<Child>
    {
        public ChildValidator(Parent parent)
        {
            RuleFor(model => model.ChildProperty).NotEmpty();
            RuleFor(model => model.Birthday).Must(birthday => parent.Birthday < birthday);
        }
    }
    

    SetCollectionValidator 已弃用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 2012-07-13
      相关资源
      最近更新 更多