Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent validator to check if entity with ID exists in database

I'm trying to write a custom validator that will check if an entity exists in the database, using OrmLite. The problem is that the type arguments for IRuleBuilder can no longer be inferred from usage.

I have to write the method call like this:

RuleFor(r => r.Id).Exists<DtoName, int, EntityName>()

But I want to write it like this:

Rulefor(r => r.Id).Exists<EntityName>()

This happens because IRuleBuilder has two type parameters and the method is an extension method. Is there a smart, fluent way to design this and make the function call preferably like the second version?

Here is code for my extension method and my validator:

    public static class AbstractValidatorExtensions
    {
        public static IRuleBuilderOptions<T, TProperty> Exists<T, TProperty, U>(this IRuleBuilder<T, TProperty> ruleBuilder)
        {
            return ruleBuilder.SetValidator(new EntityExistsValidator<U>());
        }                
    }

    public class EntityExistsValidator<T> : PropertyValidator
    {
        public EntityExistsValidator() : base("Entity does not exist") {}

        protected override bool IsValid(PropertyValidatorContext context)
        {
            return HostContext.Resolve<Repository>()
                .Exists<T>((int)context.PropertyValue);
        }
    }
like image 337
glazjoon Avatar asked Oct 14 '25 07:10

glazjoon


2 Answers

My experience with FluentValidation is that you’re trying to push more and more logic into validators. I would not do this as it adds too much complexity. My rule of thumb is to validate discrete property values only. Example: I would just use FluentValidation to check if property int Id is 0 or greater than 0. The check if the entity already exists I would move to another service (often called “the business logic”).

like image 135
thomasgalliker Avatar answered Oct 17 '25 01:10

thomasgalliker


You'll need to a Custom Validator for custom validation to access dependencies, something like:

RuleFor(x => x.Id)
    .Must(id =>
    {
        using (var db = HostContext.AppHost.GetDbConnection(base.Request))
        {
            return !db.Exists<EntityName>(x => x.Id == id);
        }
    })
    .WithErrorCode("AlreadyExists")
    .WithMessage("...");

I'd also consider just doing validation that use dependencies in your Services instead:

if (Db.Exists<EntityName>(x => x.Id == request.Id))
    throw new ArgumentException("Already Exists", nameof(request.Id));
like image 26
mythz Avatar answered Oct 17 '25 02:10

mythz