简体   繁体   English

FluentValidation-以嵌套结构将上下文从父级带入子级的最佳方法

[英]FluentValidation - Best approach to take context from the parent into the child in a nested structure

Problem 问题

I have nested parent-child relationship in my classes and would want to take the parent's context into the child. 我在班级中嵌套了父子关系,并希望将父级的上下文带入子级。 A solution that I have is to create a validator for the child for every child instance. 我有一个解决方案是为每个子实例为该子实例创建一个验证器。 It works, but since validators are stateless by nature, they should be single-instance for an application. 它可以工作,但是由于验证器本质上是无状态的,因此对于应用程序,它们应为单实例。

Parent and Child Classes 父母与子女班

public class Parent
{
  public string Id {get; set;}
  public List<Child> Children {get; private set;} = new List<Child>();
}

public class Child
{
  public string Name {get;set;}
}

Validators 验证者

Simple solution with multiple allocations on ChildValidator 在ChildValidator上进行多种分配的简单解决方案

public class ParentValidator : AbstractValidator<Parent>
{
  public ParentValidator()
  {
    // We shouldn't create a new instance of ChildValidator for each child
    RuleForEach(m=> m.Children)
      .SetValidator(m=> new ChildValidator(m.Id));
  }
}

public class ChildValidator : AbstractValidator<Child>
{
  public ChildValidator(string parentId)
  {
    RuleFor(m=> m.Name)
      .NotEmpty()
      .WithMessage($"Parent {parentId} | {PropertyName} must not be empty");
  }
}

Potential solution 潜在解决方案

One solution I have in mind is to use value tuples. 我想到的一种解决方案是使用值元组。

public class ParentValidator : AbstractValidator<Parent>
    {
        public static ParentValidator Instance { get; } = new ParentValidator();

        public ParentValidator()
        {
            // Must create as tuple (allocate) then convert to value tuple
            RuleForEach(m => m.Children.Select(c => new Tuple<Parent, Child>(m, c).ToValueTuple()))
                .SetValidator(ChildValidator.Instance)
                .OverridePropertyName("Child");

        }
    }

    public class ChildValidator : AbstractValidator<(Parent Parent, Child Child)>
    {
        public static ChildValidator Instance { get; } = new ChildValidator();

        public ChildValidator()
        {
            RuleFor(m => m.Child.Name)
               .NotEmpty()
               .WithMessage(m => $"Parent {m.Parent.Id} | {{PropertyName}} must not be empty");
        }
    }

Caveats 注意事项

However, I find this rather troublesome due to expression trees not supporting them yet as of C# 7.3. 但是,我发现这很麻烦,因为从C#7.3开始,表达式树还不支持它们。 We're now allocating Tuples instead of ChildValidator s which defeats the purpose. 现在,我们分配了Tuples而不是ChildValidator ,这违背了此目的。 Also, the error message is kind of ugly because the default property name for Child becomes Item2 另外,错误消息有点丑陋,因为Child的默认属性名称变为Item2

Test code can be accessed here 测试代码可以在这里访问

Any data from the "parent" entity that is required to validate the "child" entity should be included in the view model for the child entity. 验证“子”实体所需的任何来自“父”实体的数据都应包含在该子实体的视图模型中。

Information required for the validation messages in the child entity should also be properties on the child view model: 子实体中的验证消息所需的信息也应该是子视图模型的属性:

public class AddEditChildViewModel
{
    public int ParentId { get; set; }

    public string ParentName { get; set; }
}

Then your validator doesn't have to jump through any hoops to validate data or display validation messages: 然后,您的验证程序就不必跳过任何圈来验证数据或显示验证消息:

public class AddEditChildViewModelValidator : AbstractValidator<AddEditChildViewModel>
{
    public AddEditChildViewModelValidator()
    {
        RuleFor(m => m.ChildProperty)
            .Must(DoSomethingWithParentEntityData)
            .WithMessage("{0} {PropertyName} is required.", m => m.ParentName);
    }

    private bool DoSomethingWithParentEntityData(AddEditChildViewModel model, int childProperty)
    {
        // use model.ParentId for something
    }
}

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

相关问题 从父级上下文引用`this`子级 - Referencing to `this` child from parent context FluentValidation MustAsync子节点丢失父属性值 - FluentValidation MustAsync child loses parent property value 更新父表时更新子表的最佳方法是什么? - What is the best approach to update child table when updating parent table? FluentValidation中每个自定义规则的客户端验证的最佳方法 - Best approach for Client-side validation for each custom rule in FluentValidation 将数据库上下文从控制器传递到模型的最佳方法 - Best approach to pass database context from controller to model WebAPI-FluentValidation-根据父模型值验证子模型属性 - WebAPI - FluentValidation - Validate Child model properties based on parent model value FluentValidation,如何在子验证程序异常消息中包括父属性名称 - FluentValidation, how to include parent property name in child validator exception message FluentValidation:在子集合规则中使用父属性值 - FluentValidation: Using a parent property value in a child collection rule 嵌套的ObservableCollection - 从子到父的Propogate通知 - Nested ObservableCollection - Propogate notification from child to parent 将父子结构转换为子父级 - Transform a parent child structure to child parent
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM