【问题标题】:FluentValidation Validate object by idFluentValidation 通过 id 验证对象
【发布时间】:2016-02-10 23:25:16
【问题描述】:

使用 FluentValidation,我通常会在命令中传递 ID 和对象。但是我想验证具有 id 的对象是否存在,然后验证该对象。

有没有比下面的方法更好的方法?

    public class ProjectIdValidator : AbstractValidator<int>
    {

        public ProjectIdValidator(MyDbContext aDbContext)
        {
            Custom(aProjectId =>
            {
                var project = aDbContext.Projects.Find(aProjectId);
                if (project == null)
                {
                    return new ValidationFailure("ProjectId", "Project does not exist");
                }
                var projectValidator = new ProjectValidator();
                var x = projectValidator.Validate(project);
                if (x.IsValid)
                {
                    return null;
                }

                return new ValidationFailure("ProjectId", x.Errors.ToString());

            });
        }
    }

【问题讨论】:

    标签: c# fluentvalidation


    【解决方案1】:

    这样的事情呢?

    public class UpdateProjectCommandValidator : AbstractValidator<UpdateProjectCommand>
    {
        public UpdateProjectCommandValidator(DbContext dbContext) {
            RuleFor(x => x.Id)
                .MustFindProjectById(dbContext);
        }
    }
    

    那么您的 MustFindProjectById 扩展方法将如下所示:

    public static class MustFindProjectByIdExtensions {
        public static IRuleBuilderOptions<T, int> MustFindProjectById<T>
            (this IRuleBuilder<T, int> ruleBuilder, DbContext dbContext) {
            return ruleBuilder.SetValidator(new MustFindProjectById(dbContext));
        }
    }
    

    ...它只是一个自定义 PropertyValidator 的包装器:

    internal class MustFindProjectById : PropertyValidator {
        private readonly DbContext _dbContext;
        internal MustFindProjectById(DbContext dbContext) {
            _dbContext = dbContext;
        }
    
        protected override IsValid(PropertyValidatorContext) {
            var projectId = (int)context.PropertyValue;
            var entity = dbContext.Projects.Find(projectId);
            return entity != null;
        }
    }
    

    【讨论】:

    • Dan 可以查看对象是否存在,但我也想验证现有对象。
    • @StevenT.Cramer 那么,在应用命令时,您想在应用命令之前对数据库中已有的数据运行验证规则吗?对我来说听起来不对,所以也许我对这个问题了解不够。
    • 假设您有带有 OrderId 和 CustomerId 的 ShipOrdertToCustomerCommand。因此,要使此命令有效,具有 CustomerId 的客户必须存在并且具有有效的送货地址。只是一个例子。
    【解决方案2】:

    经过一些研究,我认为这是一个更好的方法。

    AddRule(new DelegateValidator<Command>((aCommand, aContext) =>
    {
        // return an IEnumerable<ValidationFailure> from in here:
        var projectId = (int?) aCommand.ProjectId;
        if (projectId.HasValue)
        {
    
            using (var dbContextScope = aDbContextScopeFactory.CreateReadOnly())
            {
                MyDbContext dbContext = dbContextScope.DbContexts.Get<MyDbContext>();
                Project project = dbContext.Projects.Find(projectId);
                if (project == null)
                {
                    return Enumerable.Repeat(new ValidationFailure("ProjectId", "ProjectId not found"),1);
                }
    
                var projectValidator = new ProjectValidator();
                var results = projectValidator.Validate(project);
    
                return results.Errors;
            }
        }
        return null;
    }));
    

    【讨论】:

    • 您真的想要为每个验证规则创建一个新的DbContext 实例吗?有一个请求范围的DbContext 可以重复用于所有命令验证(以及验证通过后的命令数据库操作)不是更好吗?
    • @Dan 是的,这很好。这只是示例代码,但 Get 如果已经在范围内,将重用现有上下文。 mehdi.me/ambient-dbcontext-in-ef6 有一个不错的博客。
    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2023-02-21
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 2012-10-23
    • 1970-01-01
    相关资源
    最近更新 更多