Reputation: 4984
I have a pretty common situation in which I need to validate when a reference property is being set in a given entity. When this happens I validate like this:
public class Validator : AbstractValidator<Command>
{
public Validator()
{
...
RuleFor(user => user.EmployeeId)
.MustNotBeEmpty()
.MustAsync(ExistInDatabase).WithMessage("Employee not found");
}
public async Task<bool> ExistInDatabase(Command command, string id, CancellationToken cancelation)
{
return await _context.Employees.AnyAsync(x => x.Id == id.ToGuid());
}
}
This and other check in database are so much common and I'm writing methods like this in almost every validator.
I would like to turn this into an extension method, in which I would pass the entity type, the context and the id.
A FluentValidation
extension method looks like this:
public static IRuleBuilderOptions<T, string> MustNotBeEmpty<T>(this IRuleBuilder<T, string> rule)
{
return rule
.NotEmpty().WithMessage("O campo '{PropertyName}' não pode ser vazio");
}
But these extension methods already receive generic types and I'm not figuring out how to pass another generic type to use with context.Set<T>().AnyAsync(...)
How could it be done?
----- UPDATE -----
I tried adding another generic type T2
to the extension method but it does not work:
public static IRuleBuilderOptions<T, string> MustExistInDatabase<T, T2>(this IRuleBuilder<T, string> rule, DatabaseContext context) where T2: BaseEntity
{
return rule.MustAsync(async (command, id, cancelation) => await context.Set<T2>().AnyAsync(x => x.Id == id.ToGuid())).WithMessage("'{PropertyName}' not found in database");
}
When I try to call it, the compiler complains that it could not found such extension method:
public class Validator : AbstractValidator<Command>
{
public Validator()
{
...
RuleFor(user => user.EmployeeId)
.MustNotBeEmpty()
.MustExistInDatabase<Employee>();
}
}
Upvotes: 3
Views: 2063
Reputation: 3455
I have the same issue and ends up doing this
public static IRuleBuilderOptions<T, Guid> MustExistInDatabase<T, TEntity>(this IRuleBuilder<T, Guid> ruleBuilder, DbSet<TEntity> dbSet) where TEntity : class
{
return ruleBuilder.Must(id => dbSet.Find(id) != null).WithMessage("'{PropertyName}' {PropertyValue} not found.");
}
Then
RuleFor(r => r.EmployeeId).NotEmpty().MustExistInDatabase(context.Employees);
Upvotes: 2