Domain Models with Complex Properties Construction in C#

cdesigndomain-driven-designdomain-modeldto

According to this article: Using Ids in Domain Models is not a good practice.
We should reference the entire domain model instead.

In this case, when we want to provide only Getters for our properties, we have no choice but to use the constructor parameters to pass all the data.

example :

class Car {

    public Car(string name, Model model, Engine engine){
        Name = name;
        Model model = model;
        Engine = engine;
    }

    public string Name {get;}
    public Model Model {get;}
    public Engine Engine {get}
}

In a case where we receive a DTO from the front end for example:

class CarDto {
    public string Name {get;set;}
    public long ModelId {get;set;}
    public long EngineId {get;set;}
}

How to construct the domain model from this?

  • Should we fetch the Engine and Model from the database by their ids before building the domain model ?

Also in the case when in our Domain Model we have some complex properties that are not always set, is it enough to just pass null as a parameter, or they shouldn't appear at all in the constructor, and give them a Setter ?

Any other suggestion is welcome.

Best Answer

Q: Should we fetch the Engine and Model from the database by their ids before building the domain model ?

Yes, this's what repositories do. If Car is an aggregate, the repository should be capable of fetching whatever Car needs for its initialization. It might load Engine and Model directly from the data store or ask for them to other components. You also could use services to retrieve Engine and Model and send'em to the repository alongside with the attribute name.

Q: Also in the case when in our Domain Model we have some complex properties that are not always set, is it enough to just pass null as a parameter, or they shouldn't appear at all in the constructor, and give them a Setter ?

If any of the attributes are optional, it's important to make this as clear and explicit as possible. This said, it's preferable to take them off the constructor and define setters (or methods with the due parametrization) because it simplifies the code and improves readability.

To initialise entities in different states, you could overload constructors or create static factory methods.2

If you are concerned about the access to the setters you have different ways to control it. The first that comes to mind is through access modifiers. However, you could rely on well-known OOP design practices (inversion of control or interface segregation to mention any) or design patterns.1

S: Using Ids in Domain Models is not a good practice

That's fairly true, overall when we turn the persistence model into the domain one. In such cases, the implementation details of the persistence bypass the boundaries of the persistence and become part of the implementation detail of the domain too. Raw strings and numbers become identifiers when, from the DDD standpoint, they are most likely the worst representation for an identifier. In DDD, identifying entities and aggregates might take something else than a simple string.

Since @Casablanca has mentioned Vaughn Vernon, I will share another link where he speaks about correlating boundaries (aggregates) through identifiers.


1: Defensive programming as security is a matter of costs vs benefits. Don't go crazy making everything private (narrowing down scopes to the absurd) at expenses of simplicity and readability. Unless you have a good reason for it.

2: Some languages implement the notion of optional parameter. As soon the intention is clear (what's optional and what's not), these parameters should work too.