If a domain class will validate can I be assured it will save (assuming nothing super-drastic like the database is down)? More explicitly, under which scenarios will an object pass validation but throw an error on save.
under which scenarios will an object pass validation but throw an error on save.
Domain class constraints can check anything, so if "the thing they check" changes between the calls to validate() and save(), then it's entirely possible that the former will succeed and the latter fails.
Here's a very simple such example
Book.ISBN has a unique contraint
myBook.validate() is called and passes
another book with the same ISBN as myBook is saved
myBook.save() fails because the unique constraint on ISBN now fails
Save will throw an error if your database has additional constraints that don't allow the insert or update to succeed. If your database doesn't have any additional constraints and barring any sort of infrastructure outages, I can't think of any reason save() would fail if validate() is true.
Related
Springboot: I got a mocked service and a method needs to return a javax.validation.ConstraintViolationException in order to properly unit test the caller class.
I cannot seem to find a way to generate a ConstraintViolationException or ConstraintViolation for that matter in Hibernate Validators.
Is there some solution I missing out?
Thank you
What do you want to achieve exactly?
Because you can create a ConstraintViolationException without any violations in it if you just need the exception.
If you want a violation in it (you just have to pass a set of violations to the constructor), I would say you have several possibilities:
You can simply implement ConstraintViolation as it's an interface and just put some code where you see fit.
Otherwise, I would trigger a real validation (with Validator.validate(myBean)) and get the violations from there.
You can use ConstraintViolationImpl#forBeanValidation() to forge a violation but it's an internal class so it might break in future versions of HV.
I'm not sure if this is limited to Yii2 or if it could be also discussed with other frameworks or even in general.
In Yii2 I can call validate() on a model object. This will return true or false. If it is false I can call getErrors() to see which validation problems currently exist within this object.
Why is this behavior implemented this way? Why does validate() not throw some ValidationExceptions? I find it also somehow strange that errors are part of the model object. Why are they not part of such an exception?
What are the advantages of this implementation? Why is it done this way? I would prefer exceptions. With this, I could better distinguish between desired and exceptional processing. All that is not desired is handled in catch blocks. The desired happens in try blocks. Isn't this a good idea?
Because in general the errors are used in combination with a form.
Let's say you have a form with some input fields (linked to the model attributes/properties) and you want to do something with these fields, maybe save them or something.
Before saving the fields you would like to verify that they are all valid. When the validate() method is called all attributes are validated one by one and each one will generate an error if needed. If the validation is false and you have an error collection you can again show the form, but this time attach the errors to the fields.
If you throw an exception each time an error occurs your application would stop running and only display the one error. Or you would have to write try-catch blocks for all attributes, which is just unnecessary. When your validation returns true you can run the next step which does the processing and you can be sure all values are valid.
If you really want exceptions you can, of course, write your own Validators (http://www.yiiframework.com/doc-2.0/yii-validators-validator.html)
As far as I can see, the validation within Entity Framework is built entirely around the assumption that, if an item fails its validation, it must not be persisted to the database. Is there any mechanism, possibly running parallel to normal validation, of making a constraint on a field produce a warning to the user, rather than an error which prevents the record from being saved/updated?
To be more specific, I have a situation where a particular numerical field has limits on it, but these are advisory rather than hard-and-fast. If the user enters a value outside these limits, they should get a warning, but should still be able to save the record.
In theory, I could subclass the ValidationResult class to make, say, a ValidationWarning class, then create a custom subclass of ValidationResults whose IsValid property was sensitive to the presence of ValidationWarning messages, and ignored them in deciding whether the entity is valid. However, this requirement has arisen in a project which is already someway along in its development, and it would require a lot of refactoring to make this kind of custom subclassing work properly. I would prefer to find a mechanism which could be levered in without creating that much disruption/rework.
I had a similar requirement on a project and how I solved it was this. If (ModelState.IsValid) is false, I cleared out the errors out of the ModelState and sent it on its way again,then logged the "error" to another service. This is a bit of a hack and I would'nt recommend doing as it is not exactly best practice.
I have a question related to entity validation. As an example, there is a User which can be registered into a system given email and password. The business rule says that:
email must be valid (must conform to email format) and unique;
password should be between 6 and 20 characters.
My initial thought is to place the validation inside the User.Register(email, password). The main advantage of this approach is that User controls how it is registered by verifying itself the correctness of registration data. The disadvantage is that email uniqueness verification requires calls to UserRepository, so the User might have dependency on its Repository. To solve this issue, email and password validation might be factored out to some kind of BusinessRule objects. So the validation in User.Register() method might look like this:
var emailValidationErrors = _emailRule.Validate(email);
var passwordValidationErrors = _passwordRule.Validate(password);
where _emailRule and _passwordRule might be passed as constructor arguments: User(EmailRule emailRule, PasswordRule passwordRule).
In this casse User is not directly coupled to UserRepository. In this way the rules are explicitly shown in the domain, which make it more expressive.
So the question is: what do you think about this approach? Are there any other solutions?
You could implement a Domain Service that encapsulates this. Typically in DDD you would use a Domain Service when the business logic falls outside of the scope of one individual aggregate; in this case it is the uniqueness check. So, what I'd do is:
public class UserRegistrationService : IUserRegistrationService
{
private readonly IUserRespository _userRepository;
public void Register(string email, string password)
{
if (!_userRepository.DoesEmailExist(email))
throw new Exception("Email already registered");
User user = User.Create(email, password);
_userRepository.Save(user);
}
}
Also, if you are worried about User.Create being called outside of the registration service and therefore escaping the uniqueness check, you could possibly set the User.Create method to internal, meaning the only way to create a user is via the RegistrationService.
There are three validations that you're trying to do in this example:
Email address must be a valid format;
Email address must be unique (i.e., there isn't an existing user who has that email address);
Password must conform to certain length constraints.
1 and 3 above are simple validations that should be able to be done declaratively on the entity properties (using custom attributes and a suitable validation library in .NET for example).
2 above is the tricky bit, and that's where the intrinsic dependency on the User repository exists in my opinion.
The question is: "Does the responsibility of preventing the creation of a User with the same email address as an existing User lie with the User entity?". I believe the answer to that question is "No" ... it "feels" like this responsibility should lie with a higher-level service or entity for which it is natural to have knowledge of the whole set of users.
So, my take is:
Place those validations that sit with the user inside the User entity (strong cohesion);
Place the uniqueness constraint in a DDD service that is specifically responsible for maintaining the invariants of the set of users--it would do this by wrapping the uniqueness check and the persistence of the new User in a transaction.
You can kind of think there are 2 kinds of validation: internal state validation, and context validation. You can perform internal validation from within that entity, and then perform context validation using some service.
Markus,
His approach was not bad, but I just do differently.
In my opinion you respect the OCP, putting validation rules out of the Entity, which was wisely decided. Using these validation rules in the class constructor you are suggesting that the rules are immutable, right?
I would not do this way, just create a method dyad setting the rules as this constructor. For me it was not clear what would happen if the validation rules were violated. I like to throw exceptions to the user interface that handles as more ubiquitous warnings.
Another thing that was not clear to me is the event that triggers this validation. it would be when the entity User was added to the repository or have a method of the entity that would do this? I'll take the second option calling the method isValidAuthentication() throwing that exceptions.
Regarding the dependence of the Entity to the Repository, I venture to say that is wrong. You could even make the entity dependent on him, because the repository is a collection of objects, what's wrong with this? However, at this point seems clear that validation is a Service. So if we put these validations in a Service would eliminate this coupling and apply the OCP again. Do you agree?
A big hug and success!
Suppose I have a service StateService which has a method ChangeState.
ChangeState(State toState, DomainObject object)
I have business rules that checks whether the destination state is valid or not in the domain objects current "state", how can I technically check those rules without first setting the toState on the domain object? It feels wrong to first set the new state, run validation and if one or more rule breaks unset the state.
One solution I came up with is to create some context object that drives the validation eg.
ChangeStateContext that contains the DomainObject along with the State that is to be set.
Another related question is how to report back from the ChageState call how it went?
I can collect all validation rules that broke and throw an exception with those rules that the caller can catch and handle accordingly or I can add a return type on the ChangeState-method like ValidationSummary that contains information about broken rules and such. What is best practices in these cases?
Can't you throw an exception from the ChangeState method when the state transformation is invalid? You can throw specific exceptions such as StateTransformationException or ValidationException that you can catch higher on the call stack. You can optionally include extra properties to these exception types so that you can communicate very precisely what went wrong to the user.
When you want to call multiple ChangeStates after a single user action, you will need a way to revert or rollback. What I usually do is using the unit of work pattern (supplied to me by LINQ to SQL and Entity Framework) and change all state within this unit of work. When an exception is thrown I throw away the complete unit of work with all its changes.
The DomainObject class could have a public bool CanChangeState(State toState) instance method, returning True if toState is a valid transition from the current state of the subject DomainObject. Such method can be called prior to the StateService.ChangeState call.
Of course, if the StateService is responsible for the state change validation, then a CanChangeState(State toState, DomainObject obj) method should be added to the StateService.
To report back the validation error messages, change the return Type of the CanChangeState to a custom Type responsible for reporting validation errors.