10
votes

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?

4
Also see this answeroleksii

4 Answers

9
votes

A pattern I use in these types of situations is to place this type of validation logic in the application service. To some extent, this makes sense because the User entity is only responsible for its own validity, not the validity of the set of users. The application service method that creates the user can looklike this:

public User CreateUser(string userName)
{
  if (this.userRepository.Exists(userName))
    throw new Exception();
  var user = new User(userName);
  this.userRepository.Add(user);
  return user;
}

The application service is an abstraction that is there regardless of whether you are employing DDD or no and is therefore a good place to fall back to when DDD gives friction.

8
votes

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.

4
votes

However this seems ... well wrong

No, it's not wrong at all. Having the domain model depend on a repository is perfectly fine. In addition to that you have abstracted your repository behind an interface which is even better.

Or don't use constructor injection. Pass the repository to the Validate method if it is the only one needing it:

public class User
{
    public void Validate(IUserRepository repo)
    {
        //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 = repo.GetUserByUsername(Username);
        if (user != null && user.id != id)
            throw new ValidationException("Username must be unique")
    }
}
1
votes

I agree with @oleksii, using the specification pattern is a better approach. Validation has different meanings in different contexts, so it makes sense to me to split this concern.