[英]FluentValidation - Best approach to take context from the parent into the child in a nested structure
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. 它可以工作,但是由于验证器本质上是无状态的,因此对于应用程序,它们应为单实例。
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;}
}
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");
}
}
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");
}
}
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
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.