Relational database developers have long used the term “Entity” when designing database schemas. Meanwhile, on the software architecture side, the term “Entity” is a key component of domain-driven design. So what is the difference? Or is there a difference? Do they refer to the same thing?
Database Entities represent objects in the real world or the application domain. This might be something physical such as a customer or a vehicle, but it can also be something conceptual such as an order or a schedule.
These entities (and the relationships between them) are often drawn using an Entity-Relationship Diagram such as the one below. In this diagram, we’ve drawn two entities, an order, and an order_item. We’ve colored both grey.
Each entity has a primary key that uniquely identifies it. We’ve used pink to highlight the primary keys.
We also want to store various attributes of the entity. In our order_item, this includes details such as the product, price, and quantity. We’ve drawn these in blue.
To create relationships between entities, we use a foreign key. In our example, each order_item is assigned to a specific order. We reference this order by storing its order_id as a foreign key, highlighted in yellow. These relationships are generally unidirectional. However, there are techniques to create bidirectional relationships as well.
When we translate the entities into the database, the table represents a collection of similar entities, also known as an entity set. Each row in the table is an individual entity. The columns record the attributes of the entity.
From these details, we can tease out a concrete definition.
A relational database entity is a representation of a real object that is uniquely identifiable and contains attributes of interest to our application, including its relationship to other entities. It is represented in the database by individual rows in a table.
A simple definition of an entity in domain-driven design is that it is an object in the domain that is defined by its identity, rather than its attributes.
To give an example, we can talk about a real estate property. Specifically, one that has a house built on it. The identity of a property is generally given by its address (eg. 102 Cockroach Lane). That address uniquely identifies the property. Individual attributes can change. You could plant trees, paint the house, add a pool, or even tear down the house completely. No matter what you do to it, it’s still the same property, as long as the address doesn’t change.
On the other hand, if you alter anything in the address (eg. 104 Cockroach Lane or 102 Cockroach Way), then the property has changed. You are no longer referring to the same location.
Class diagrams are a common way to represent entities in a domain-driven design context. Here we see a class diagram for our order and order items.
Much like with a relational entity, domain-driven design entities contain attributes. In our diagram, we’ve separated out the identifier for the order from the rest of the attributes. However, a domain-driven design entity contains more than just the details. It also encapsulates any operations that can be performed with the entity. We’ve included these operations in the bottom section of each class.
Similar to a relational database, domain-driven design entities can be related to each other. However, in this case, there are two types of relationships we need to consider.
Some entities will aggregate others. In this case, if the top-level entity (called the aggregate root) is deleted, then all other entities it aggregates will be deleted. We can see this with an order. It aggregates the order items. Those items can’t exist if the order gets deleted. We don’t bother defining foreign keys in this case because they are an implementation detail of a database, not part of the domain.
Some entities will only be loosely related to each other by reference. In this case, one entity contains a reference to the other (using the unique identifier of an aggregate root) but it doesn’t actually contain the other entity. If one entity is deleted, it may have no impact on the other. An order may reference a customer, but the customer can exist without the order. Here, we define the reference to the customerId in the diagram.
The implementation of a domain-driven design entity can vary dramatically depending on the technology you use. Even though we often draw them using class diagrams, they don’t have to be implemented that way. They are technology agnostic. So it might be implemented as an object in an object-oriented language. Or it might be implemented as a series of functions.
From this, we can derive a more concrete definition of a domain-driven design entity.
In domain-driven design, an entity is a representation of an object in the domain. It is defined by its identity, rather than its attributes. It encapsulates the state of that object through its attributes, including the aggregation of other entities, and it defines any operations that might be performed on the entity.
With our two definitions in mind, we can immediately see that there are some similarities between the two types of entities.
|Relational Entity||Domain-Driven Design Entity|
|Represent real domain objects||yes||yes|
|Contain mutable attributes||yes||yes|
|Reference other entities||yes||yes|
So it looks initially like there is a degree of compatibility between the two. However, there are some key differences as well.
|Relational Entity||Domain-Driven Design Entity|
|Aggregate Other Entities||no||yes|
These differences are worth digging into in a little more detail.
Encapsulating operations is a key difference between the two. In a standard relational database, entities are mapped to tables, rows, and columns. They are data containers. They aren’t meant for implementing complex operational logic. Having said that, many relational databases implement features such as triggers, stored procedures, etc. that start to encroach into this territory. So in some cases that operational logic might actually be built into the database. However, it’s not traditionally part of the relational model, and there are many debates on whether or not these techniques belong in the database. For now, we’ll simply say that the relational entity does not traditionally encapsulate those operations.
Aggregation is another interesting one. It can actually be implemented in many relational databases. Using cascading actions, we can set up our foreign keys so that if one object is deleted, that change will cascade to other related objects, causing them to be deleted as well. However, it is worth noting that in the foreign key relationship, the reality is that we aren’t dealing with an aggregation. In fact, the database doesn’t even understand things like one-to-many relationships. All it actually understands is that one record is related to another through a foreign key. The fact that this might be used to implement aggregation relationships is a property of the design, not a property of the database.
From this, what can we conclude about relational entities and domain-driven design entities? In the end, both types of entities are trying to do something very similar. They are trying to take a real-world object, and model it using the techniques available. In that regard, the goal of the two types of entities is the same. It’s only in the finer details where things start to diverge. Both types of entities are potentially modeling the same object, but we shouldn’t assume that they will create a compatible implementation.
Domain-driven design entities are used to model the domain without worrying about specific implementation details. Relational entities are more concretely about modeling the implementation of the database. We may start with domain-driven design entities, but as we dive deeper into implementation we might need to transition into working with relational entities. It is important to make sure we use the right tools for the job.
If you want to learn more about modeling entities with SQL check out the SQL Skills Path from Cockroach University. There are free tutorials and lectures in that course to get you up to speed.
This SQL cheat sheet is designed to make it quick and easy to find that SQL command that’s right on the tip of …Read More