DDD - Modelling User with contact information that must be unique across the system

963 Views Asked by At

I need some clarification on modelling a user for Identity and access domain. The user domain model has a contact information entity (entity because it is mutable), the customer can register with a phone number, but can choose to change it when needed.

The phone number once used by a customer can never be used by any other user. So the model I believe must allow querying the phonenumber table(since it is many to one with the customer, as the old numbers are deactivated and archived).

If creating a domainservice is ok, what should be the Repository as there is no aggregate identified. With these cases I have a customer(user) aggregate, but to allow querying all the users to see if the phone number provided by the customer is already been used by anyone else, what should be the aggregate, or can I write a DomainService that just can query the database directly to the phonenumber table to check for the uniqueness, am I violating any DDD principle doing so, what are the cleaner alternatives.

2

There are 2 best solutions below

9
On

An alternative would be to create an Aggregate that makes it explicit in which scope you intend the unique constraint to hold.

As a (contrived) example, a phone number might be unique across a country but not internationally. Thus :

// An Aggregate Root
public class Country {

  // Store a lookup structure (userId, phoneNumber) here

  public void addUser(userId, phoneNumber) {
    // check phone uniqueness here
  }

  public void changeUserPhone(userId, phoneNumber) {
    // check phone uniqueness here
  }
}

Since you're using CQRS, phone numbers being in a separate Aggregate doesn't matter because on the Query side, Read Models will reassemble the User and their phoneNumber together.

This also plays well with the "don't create Aggregate Roots" approach since you have a starting point from where to create your User (User is probably an AR) and not just create it out of thin air.

0
On

You could have your repository check if the phone number exists, if it does then throw a rule exception else save the change. The key here is to inject an instance of the repository through the application layer and run rule inside the domain layer.