在我的项目中,我使用 Fluent Validation 来定义自定义验证规则。我注意到,在许多验证规则中,需要从数据库中检索值来执行验证。问题是我在各种规则内多次从数据库检索数据,这可能会影响性能。
我想知道是否有一种方法可以从数据库中执行一次数据检索,并在所有验证规则中使用它,从而避免重复检索数据。
在搜索中我发现一种可能的解决方案是初始化头部中的变量,但我对此不太确定
您始终可以注入自定义单例服务,该服务可以在验证器之间缓存和共享结果。
您可以从对每个属性使用单独的规则转变为对整个经过验证的对象使用单个自定义规则。
假设我们正在验证将学生注册到课程的命令。新学生注册课程的规则是:
如果您使用多个规则,则需要重复调用才能从数据库中检索学生:
public class EnrollStudentInCourseCommandValidator : AbstractValidator<EnrollStudenInCourseCommand>
{
public EnrollStudentInCourseCommandValidator(
IUnitOfWork unitOfWork)
{
RuleFor(x => x.StudentId)
.MustAsync(async (studentId, ct) => unitOfWork.Students.GetStudentByIdAsync(studentId) is not null)
.WithMessage($"Student with id {PropertyName} does not exist.");
RuleFor(x => x.CourseId)
.MustAsync(async (command, courseId, ct) =>
{
var student = await unitOfWork.Students.GetStudentByIdAsync(command.StudentId);
if (student is null)
return true; // handled above
return !student.Courses.Any(c => c.Id == courseId);
})
.WithMessage($"Student is already enrolled in course with id {PropertyName}.");
}
}
如果我们使用单个 CustomAsync 规则,我们可以引用验证第一个规则时检索到的同一学生:
public class EnrollStudentInCourseCommandValidator : AbstractValidator<EnrollStudenInCourseCommand>
{
public EnrollStudentInCourseCommandValidator(
IUnitOfWork unitOfWork)
{
RuleFor(x => x)
.CustomAsync(async (command, context, ct) =>
{
var student = unitOfWork.Students.GetStudentByIdAsync(studentId);
if (student is null)
{
context.AddFailure(nameof(command.StudentId), $"Student with id {command.StudentId} does not exist.");
return;
}
if (!student.Courses.Any(c => c.Id == courseId))
{
context.AddFailure(nameof(command.CourseId), $"Student is already enrolled in course with id {command.CourseId}.");
return;
}
});
}
}