Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DDD Domain Model Complex Validation

I am working on rewriting my ASP.NET MVC app using the domain driven design priciples. I am trying to validate my User entity. So far I am able to validate basic rules (like the username and password being a non null/whitespace string). However one of the rules, I need to make sure that the username is unique. However I need access to the database inorder to do this, which means I would have to inject my IUserRepository into my User entity like so.

public class User
{
    private readonly IUserRepository _userRepository;
    public User(IUserRepository repo)
    {
        _userRepository = repo;
    }

    public override void Validate()
    {
        //Basic validation code
        if (string.IsNullOrEmpty(Username))
            throw new ValidationException("Username can not be a null or whitespace characters");
        if (string.IsNullOrEmpty(Password))
            throw new ValidationException("Password can not be a null or whitespace characters");

        //Complex validation code
        var user = _userRepository.GetUserByUsername(Username);
        if (user != null && user.id != id)
            throw new ValidationException("Username must be unique")
    }
}

However this seems ... well wrong. Making my entity depend on my repository seems like a bad idea (correct me if I am wrong). But having the validation code in the entity makes sense. Where is the best place to put complex validation code?

like image 677
Stefan Bossbaly Avatar asked Aug 14 '12 17:08

Stefan Bossbaly


People also ask

How are domain models validated?

Implement validations in the domain model layer. Validations are usually implemented in domain entity constructors or in methods that can update the entity. There are multiple ways to implement validations, such as verifying data and raising exceptions if the validation fails.

What is domain in DDD principle?

Domain-Driven Design(DDD) is a collection of principles and patterns that help developers craft elegant object systems. Properly applied it can lead to software abstractions called domain models. These models encapsulate complex business logic, closing the gap between business reality and code.

What is context of validation?

Messages in Context Validation. Messages is an object that represents the validation state builder. It provides an easy way to collect errors, warnings, and information messages during validation. Each Messages object has an inner collection of Message objects and also can have a reference to parentMessages object.


1 Answers

However this seems ... well wrong. Making my entity depend on my repository seems like a bad idea (correct me if I am wrong).

In general, dependency on repository is not 'wrong', it is sometimes unavoidable. However I think it should be an exception and should be avoided as much as possible. In your scenario you may reconsider having this dependency. If you think about it, 'uniqueness' is not a responsibility of the entity itself because entity does not know about other entities. So why having entity enforce this rule?

But having the validation code in the entity makes sense. Where is the best place to put complex validation code?

I think that you may be overgeneralizing 'validation'. I would get rid of the 'Validate' method and will make sure that the object does not get into 'invalid' state in the first place. I answered similar question few months ago.

Now back to the uniqueness rule. I think that this is one of the examples where DDD 'leaks' a bit, in a sense that the enforcement of this business rule can not be expressed purely in domain code. I would approach it like this:

// repository
interface Users {
  // implementation executes SQL COUNT in case of relation DB
  bool IsNameUnique(String name);

  // implementation will call IsNameUnique and throw if it fails
  void Add(User user);
}

The client code would know that before adding a new user, it should explicitly check for uniqueness, otherwise it will crash. This combination enforces business rule in the domain code, but it is usually not enough. As an additional enforcement layer you may want to add UNIQUE constraint in the database or employ explicit locking.

like image 120
Dmitry Avatar answered Sep 19 '22 17:09

Dmitry