Repository pattern and 1:1 relationships - domain-driven-design

I currently create a Repository for each database table and a corresponding data class for the column values (object to pass around data).
I recently started using some 1 to 1 relationships and I'm not sure what would be the best way to implement them.
For example
If I have a User table and a UserSettings Table in a 1:1 relationship.
// Data classes (Holds all the field value for the table)
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
}
public class UserSettings
{
public int UserId { get; set; }
public bool SomeSetting { get; set; }
}
Questions:
Should I always go through the User object to manipulate the UserSettings object, or should I be able to manipulate them
independently?
Should I include the primary key field in the UserSettings object?
Should I store a reference to the USerSettings object in the User object?
Do I make two repo's one for User and one UserSettings, or do I handle everything in the Users Repo.

The only time I've ever found a 1:1 relationship between aggregate roots to be useful is when the aggregate roots on either side of the relationship are managed by different domains. They must share the same primary key, and therefore if they are both managed by the same domain then they are by definition parts of the same aggregate root. I think you need to approach this question from a different angle:
Is the User object only going to exist for this application?
Do you expect that to always be the case?
If the User is a concept that resides entirely inside of this domain, then there's no reason to have a UserSettings aggretate root that has a 1:1 relationship with a User; you simply make User.Settings a way to retrieve the UserSettings for that User. (And of course that obviates the need for a repository - it becomes the responsibility of the UserRepository to hydrate the UserSettings when it hydrates everything else on the User.)
But, if the User will eventually inform sessions for multiple domains, then User needs to represent its own domain, the services of which your application will consume. Then, you gain a very real need to separate the UserSettings of this application from those of a different application. The User is not specific to this application, but the UserSettings for that User is.
NOTE - In the interest of not refactoring your project at this point, if the answer to either question 1 or 2 above is "no", then you should make UserSettings a separate aggregate root within the same domain, in order to create a seamless transition when you eventually do move User into its own domain.

What exactly do you mean by 'going through the user object' ?
IMHO, no.
You can, but I do not think you should. Is there any reason why you'd want to know to which User the settings belong to ? The only time you'd want to know that -imho- is when you persist it. In your database, you need to know to which User, the UserSettings belong to. In your model, I think you can suffice by a uni-directional relationship
You should only create a repository per aggregate root, in your case 'User' can be an aggregate root. UserSettings is -imho- not even an entity but a value object.

I currently create a Repository for each database table
...
// Data classes (Holds all the field value for the table)
It seems you're adopting a bottom-up (database first/database centric) approach which is uncommon in DDD. As the name Domain Driven Design implies, you usually rather start by modelling your domain, fleshing out your Aggregates, Aggregate Roots and Entities.
Aggregate roots usually have their own Repository while regular entities most often don't. To know whether an entity should be an Aggregate root, you have to ask yourself if that object is going to be one of the main entry points in the application, with a group of related objects gravitating around it and only obtainable through traversal of it.
User is an obvious candidate for an Aggregate root. User Settings in contrast isn't IMO a root, it belongs in the sphere of influence of a User. I'd make it a part of the User Aggregate and only obtainable through traversal of a User. It means having a reference to UserSettings in User but not necessarily the other way around.

I would ask yourself if a UserSettings can exist with out an associated user, and/or does a User always have an associated UserSettings. If so then the UserSettings could easily be made part of the User aggregate rather then being a separate aggregate itself. Yes in the database they will most likely be in different tables with 1:1 relationship between them, but this is a specific concern of the implementation of the repository. Your domain model could consider the UserSettings part of the user.

Related

DDD Effective modelling of aggregates and root aggregation creation

We are starting a new project and we are keen to apply DDD principles. The project is using dotnet core, with EF core providing the persistence to SQL Server.
Initial view of the domain
I will use an example of a task tracker to illustrate our issues and challenges as this would follow a similar structure.
In the beginning we understand the following: -
We have a Project
Users can be associated to Projects
A Project has Workstreams
A Workstream has Tasks
Users can post Comments against a Task
A User is able to change the status of a Task (in progress, complete etc)
A Project, with associated Worksteams and Tasks is initially created from a Template
The initial design was a large cluster aggregate with the Project being the root aggregate holding a collection of ProjectUsers and Workstreams, Workstreams has a collection of Tasks etc etc
This approach was obviously going to lead to a number of contention and performance issues due to having to load the whole Project aggregate for any changes within that aggregate.
Rightly or wrongly our next revision was to break the Comments out of the aggregate and to form a new aggregate using Comment as a root. The motivation for this was that the business envisaged there being a significant number of Comments raised against each Task.
As each Comment is related to a Task a Comment needs to hold a foreign key back to the Task. However this isn't possible following the principle that you can only reference another aggregate via its root. To overcome this we broke the Task out to another aggregate. This also seemed to satisfy the need that the Tasks could be Completed by different people and again would reduce contention.
We then faced the same problem with the reference from the Task to the Workstream the Task belongs to leading to us creating a new Workstream aggregate with the foreign key in the Task back to the Workstream.
The result is: -
A Project aggregate which only contains a list of Users assigned to the project
A Workstream aggregate which contains a foreign key to the Project
A Task aggregate which contains a foreign key to the Project
A Comments aggregate which contains a foreign key back to the Task
The Project has a method to create a new instance of a Workstream, allow us to set the foreign key. I.e. slightly simplified version
public class Project()
{
string _name { get; private set;}
public Project(Name)
{
_name = Name;
}
public Workstream CreateWorkstream(string name)
{
return new Workstream(name, Id);
}
....+ Methods for managing user assignment to the project
}
In a similar way Workstream has a method to create a Task
public class Workstream()
{
string _name { get; private set;}
public int ProjectId { get; private set; }
public Workstream(Name, Id)
{
_name = Name;
_projectId = Id;
}
public Task CreateTask(string name)
{
return new Task(name, Id);
}
private readonly List<Task> _activities = new List<Task>();
public IEnumerable<Task> Activities => _activities.AsReadOnly();
}
The Activities property has been added purely to support navigation when using the entities to build the read models.
The team are not comfortable that this approach, something doesn't feel right. The main concerns are:-
it is felt that creating a project logically should be create project, add one or more workstreams to the project, add task to the workstreams, then let EF deal with persisting that object structure.
there is discomfort that the Project has to be created first and that the developer needs to ensure it is persisted so it gets an Id, ready for when the method to Create the template is called which is dependent on that Id for the foreign key. Is it okay to push the responsibility for this to a method in a domain service CreateProjectFromTemplate() to orchestrate the creation and persistence of the separate objects to each repository?
is the method to create the new Workstream even in the correct place?
the entities are used to form the queries (support by the navigation properties) which are used to create the read models. Maybe the concern is that the object structure is being influence by the how we need to present data in a read only
We are now at the point where we are just going around in circles and could really use some advice to give us some direction.
The team are not comfortable that this approach, something doesn't feel right.
That's a very good sign.
However this isn't possible following the principle that you can only reference another aggregate via its root.
You'll want to let go of this idea, it's getting in your way.
Short answer is that identifiers aren't references. Holding a copy of an identifier for another entity is fine.
Longer answer: DDD is based on the work of Eric Evans, who was describing a style that had worked for him on java projects at the beginning of the millennium.
The pain that he is strugging with is this: if the application is allowed object references to arbitrary data entities, then the behaviors of the domain end up getting scattered all over the code base. This increases the amount of work that you need to do to understand the domain, and it increases the cost of making (and testing!) change.
The reaction was to introduce a discipline; isolate the data from the application, by restricting the application's access to a few carefully constrained gate keepers (the "aggregate root" objects). The application can hold object references to the root objects, and can send messages to those root objects, but the application cannot hold a reference to, or send a message directly to, the objects hidden behind the api of the aggregate.
Instead, the application sends a message to the root object, and the root object can then forward the message to other entities within its own aggregate.
Thus, if we want to send a message to a Task inside of some Project, we need some mechanism to know which project to load, so that we can send the message to the project to send a message to the Task.
Effectively, this means you need a function somewhere that can take a TaskId, and return the corresponding ProjectId.
The simplest way to do this is to simply store the two fields together
{
taskId: 67890,
projectId: 12345
}
it is felt that creating a project logically should be create project, add one or more workstreams to the project, add task to the workstreams, then let EF deal with persisting that object structure.
Maybe the concern is that the object structure is being influence by the how we need to present data in a read only
There's a sort of smell here, which is that you are describing the relations of a data structure. Aggregates aren't defined by relations as much as they are changes.
Is it okay to push the responsibility for this to a method in a domain service CreateProjectFromTemplate
It's actually fairly normal to have a draft aggregate (which understands editing) that is separate from a Published aggregate (which understands use). Part of the point of domain driven design is to improve the business by noticing implicit boundaries between use cases and making them explicit.
You could use a domain service to create a project from a template, but in the common case, my guess is that you should do it "by hand" -- copy the state from the draft, and then send use that state to create the project; it avoids confusion when a publish and an edit are happening concurrently.
Here is a different perspective that might nudge you out of your deadlock.
I feel you are doing data modeling instead of real domain modeling. You are concerned with a relational model that will be directly persisted using ORM (EF) and less concerned with the actual problem domain. That is why you are concerned that the project will load too many things, or which objects will hold foreign keys to what.
An alternative approach would be to forget persistence for a moment and concentrate on what things might need what responsibilities. With responsibilities I don't mean technical things like save/load/search, but things that the domain defines. Like creating a task, completing a task, adding a comment, etc. This should give you an outline of things, like:
interface Task {
...
void CompleteBy(User user);
...
}
interface Project {
...
Workstream CreateWorkstreamFrom(Template template);
...
}
Also, don't concentrate too much on what is an Entity, Value Object, Aggregate Root. First, represent your business correctly in a way you and your colleagues are happy with. That is the important part. Try to talk to non-technical people about your model, see if the language you are using fits, whether you can have a conversation with it. You can decide later what objects are Entities or Value Objects, that part is purely technical and less important.
One other point: don't bind your model directly to an ORM. ORMs are blunt instruments that will probably force you into bad decisions. You can use an ORM inside your domain objects, but don't make them be a part of the ORM. This way you can do your domain the right way, and don't have to be afraid to load too much for a specific function. You can do exactly the right things for all the business functions.

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

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.
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.
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.

DDD and getting additional information in a domain class

I think I've read 16,154 questions, blog posts, tweets, etc about DDD and best practices. Apologies for yet another question of that type. Let's say I have three tables in my database, User, Department, and UserDepartment. All very simple. I need to build a hierarchy showing what departments a user has access to. The issue is that I also need to show the parent departments of those that they have access to.
Is it best to have a GetDepartments() method on my user class? Right now I have a user service with GetDepartments(string userName), but I don't feel like that is the optimal solution. If user.GetDepartments() is preferred then how do I get access the repository to get the parent departments for those that the user has access to?
Don't think it matters, but I'm using the Entity Framework.
public class User
{
[Key]
public int UserId { get; private set; }
[Display(Name = "User Name")]
public string UserName { get; private set; }
[Display(Name = "Email")]
public string Email { get; private set; }
[Display(Name = "UserDepartments")]
public virtual ICollection<UserDepartment> UserDepartments { get; private set; }
public List<Department> GetDepartments()
{
// Should this be here? and if so, what's the preferred method for accessing the repository?
}
}
DDD is more about the behavior, which also mean it is TDA (tell, don't ask) oriented.
Normally you structure your aggregates in a way that you tell them what to do, not ask for information.
Even more, if some extra information is required by the aggregate in order to perform its behavior, it is typically not their job to figure out where to get this information from.
Now, when you are saying that your User aggregate has GetDepartments method, it raises a bell. Does the aggregate need this information in order to perform any kind of behavior? I don't think so, it is just you wanting some data to display.
So what I see here is that you are trying to structure your aggregates against your data tables, not against the behavior.
This is actually #2 error when applying DDD (#1 is not thinking about bounded contexts).
Again, aggregates represent business logic and behavior of your system. Which means that you don't have to read from aggregates. Your read side can be done much easier - just make a damn query to the DB.
But once you need to ask your system to do something - now you do it through aggregates: AppService would load one from the repository and call its behavior method.
That's why normally you don't have properties in your aggregates, just methods that represent behavior.
Also, you don't want your aggregates to be mapped to the data tables anyhow, it is not their job, but the job of repositories. Actually, you don't want your domain to have dependencies on anything, especially infrastructure.
So if you want to go for DDD direction then consider the following:
Structure your aggregates to encapsulate behaviors, not represent data tables
Don't make your domain dependant on infrastructure, etc.
Make repositories to be responsible to load/save aggregates. Aggregates themselves should know nothing about persistence, data structure, etc.
You don't have to read data through aggregates.
Think of #4 as your system has two sides: the "read" side when you just read the data and show them in the UI, and the "command" side when you perform actions.
The first one (read) is very simple: stupid queries to read the data in a way you want it. It doesn't affect anything because it is just reading, no side effects here.
The second one is when you make changes and that is going through your domain.
Again, remember the first rule of DDD: if you don't have business logic and behavior to model then don't do DDD.

Domain Driven Design and local identity in an aggregate

In Domain Driven Design there is an Aggregate Root that has reference to internal entities.
Aggregate Root is an entity with global identity (everyone able to use its id). Aggregate root has links to local objects (entities).
Assuming here that Entities are the Hibernate #Entities (let's say)
Let's say we have Aggregate Root "User" that has "Address" entity in it as an object (which is actually an entity as well)
The question is:
How is it possible to make local entities to be with local identity only. I mean, there is no any barriers that could prevent anyone to use local entities (like Address) by its IDs. (so then this identity is not local at all, but global). Then, what is the way to make it local?
Well i don't think this is a matter of a public field or property or some access restriction mechanism, the way i see it "local identity" means that objects outside of the aggregate boundary can't use that local identity in a meaningful or useful way (e.g. they can't use that identity to retrieve that object or persist it to the database or any other operation). That identity doesn't mean anything to the outside world and it is only unique within that aggregate. Another example, what guarantees you that objects outside of an aggregate boundary won't hold references to objects within (which violates one of the principles of aggregates), well nothing unless those objects are VALUE OBJECTS which might not be the case every time. If i want to put that in a few words: Don't create any public APIs that use identities of objects within an aggregate , this way you will make it clear to the developer not to use those IDs.
All entities, including the root, have an identity. The fact that only the identity of the aggregate root should be used "globally" is something that cannot be easily enforced by the code itself. In a relational database in particular, every table record will have some key, regardless of whether that record stores an aggregate root, and entity or a value object. As such, it is up to the developer to discern which database identities are part of the domain and which are not.
Entities within an aggregate root are supposed to only have local identity. For all intents and purposes the database table need not have a primary key. When the aggregate is hydrated the entities within the AR should be fetched based on their link to the AR. But even that FK need not be represented in the local entity since the connection is obvious based on the containment of the local entities with the AR.
Since most database systems will moan if there is no PK on a table so you could add one for the sake thereof but you can just ignore it in your entity design. So there would be no property for the PK in the entity. The only way someone could then get to that entity is by way of the DB since there should be no way in your code to do so.

Can I call operations on Entities within an Aggregate Root?

As per the title, I have the following classes:
public class Company : AggregateRoot {
public AddressBook AddressBook { get; set; }
}
public class AddressBook {
public List<Address> Addresses { get; set; }
public Address GetPrimaryAddress() {
return Addresses.FirstOrDefault();
}
}
Is it acceptable for me to call:
company.AddressBook.GetPrimaryAddress();
Or should I expose a GetPrimaryAddress() method on Company that in turn calls the AddressBook method?
I know I shouldn't have references to entities within an AggregateRoot but I wasn't sure what the rulings are on calling operations.
Update
For what it's worth, below is a diagram (click here for full size) of my actual model. ContactList contains rules for how all types of contact (Person/Business Location) should be managed, such as what happens when a primary contact is removed. It also works around some caveats of how RavenDB stores nested entities (essentially we need to provide our own Id strategy - hence the LastContactId property).
First of all, it's all depending on the context and I assume that Company really is the AR for that specific context. The same Company can be a simple object in other contexts. Now, I'm not a fan of dogmatic use of rules and patterns so it is not important what the 'rule' says.
In this case I won't expose the Address as it seems to be an internal of the Company. As a coosnumer of the Company, I want its primary address, I don't care you're using the AddresBook to organize them.
To give a not so common example: the AR Human has two Eye objects. Will you ask the Person to give one of his eyes so you can check their color or you ask the Person directly what color his eyes are?
According to the Aggregate pattern:
Transient references to the internal members can be passed out for use within a single operation only.
Meaning - a Company can pass a reference to its Address object to other objects outside the aggregate, but Address cannot be a member of any other object outside the aggregate.
For example, an object User can ask a reference to an Address from a Company, but User cannot have Address as one of its members.
And why is that so important?
Because the root controls access, it cannot be blindsided by changes to the internals.
If an object User would have Address as one of its members, it might pull it out of the database without its Company and thus, Company would be blindsided by changes to its internals.
Please see a post I've wrote in which i demonstrate why is this principle so important.
Good question, this is one of the things I've always found hard to get right in DDD - do you always access entities through their aggregate root and probably violate the Law of Demeter at some point (AggregateRoot.EntityX.EntityY.DoStuff()) ? Do you short-circuit the aggregate root ? Do you add at the aggregate root level one direct accessor for each sub-sub-entity you want to access, muddling the aggregate root ?
One way to solve that could be : try to make every object talk only to its immediate or nearby neighbors and not to some distant stranger. Use multiple objects that each know a small part of the path from the aggregate root to the final entity you want to access.
The first object knows only the aggregate root,
It injects AggregateRoot.SubEntity1 into a second object,
Second object in turn injects SubEntity1.SubEntity2 into a third object
and so on.
Interestingly enough, one thing this reveals is the (ir)relevance of some of your domain entities. In the Address example, ask yourself if it feels right for every object that wants to access the primary Address of a Company to be injected an AddressBook. If it seems too convoluted, maybe you should not have an AddressBook in the first place. Maybe it isn't such a strong notion that it deserves to be part of the ubiquitous language after all.
Or, maybe you'll find out an AddressBook is precisely the right object to be used by your client object, and that this client object tries to do too many things at a time in manipulating both a Company and an Address.

Resources