bartoszlenar / Validot

Validot is a performance-first, compact library for advanced model validation. Using a simple declarative fluent interface, it efficiently handles classes, structs, nested members, collections, nullables, plus any relation or combination of them. It also supports translations, custom logic extensions with tests, and DI containers.
MIT License
310 stars 19 forks source link

Check single property #31

Closed kronic closed 2 years ago

kronic commented 2 years ago

How can i check one property of an object and not the whole object?

bartoszlenar commented 2 years ago

Hi @kronic

I guess you're looking for the Member command?

You have it fully documented here: https://github.com/bartoszlenar/Validot/blob/main/docs/DOCUMENTATION.md#member

Also I have it described with examples on my blog: https://lenar.dev/posts/crafting-model-specifications-using-validot#validating-members

kronic commented 2 years ago

@bartoszlenar I meant something else. Simple example

public class UserModel
{
    private readonly IValidator<UserModel> _validator;
    private string? _name;
    private string? _email;
    private int _age;

    public UserModel()
    {
        Specification<UserModel> userModelSpecification = static s => s
            .Member(static m => m.Name, static v => v.NotEmpty().LengthBetween(2, 5))
            .Member(static m => m.Age, static v => v.Between(18, 99))
            .Member(static m => m.Email, static v => v.Contains("@"));

        _validator = Validator.Factory.Create(userModelSpecification);
    }

    public string? Name
    {
        get => _name;
        set
        {
            _name = value;
            //how validate only property Name
            _validator.Validate()
        }
    }
    public string? Email
    {
        get => _email;
        set
        {
            _email = value;
            //how validate only property Email
            _validator.Validate()
        }
    }
    public int Age
    {
        get => _age;
        set
        {
            _age = value;
            //how validate only property Age
            _validator.Validate()
        }
    }
}
bartoszlenar commented 2 years ago

That's not possible. What I would do...

  1. Create specification per property (and thus, a validator per property). And then if you need also one that bundles them all, you can just merge them (see this section: https://lenar.dev/posts/crafting-model-specifications-using-validot#merging-and-extending-specifications)

  2. Validate as you do, but fail if the validation result contain errors only within a specific path. Something like

public int Age
    {
        get => _age;
        set
        {
            _age = value;

            if (_validator.Validate(_age).MessageMap.ContainsKey("Age")) throw new Exception();

        }
    }

I don't know your use case, but in general I would recommend NOT to place your validation logic in setters. Make your model anemic and validate it externally. Again - that's only a general advice, as I have no idea about your requirements.