Entity vs Value Object: A Complete List of Differences

    The topic of differences between concepts such as Entity and Value Object from Domain-Driven Design is not new. However, I could not find an article with a complete list of their differences, so I decided to write my own.

    Equivalence types


    To indicate the difference between entities and value objects, we need to define three types of equality, which take effect as soon as we try to compare two objects with each other.

    Reference equality means that two objects are equal if they refer to the same object on the heap:

    image

    Here is how we can check for reference equivalence in C #:

    object object1 = new object();
    object object2 = object1;
    bool areEqual = object.ReferenceEquals(object1, object2); // возвращает true
    

    Identifier equality implies that the class has an Id field. Two objects of this class will be equal if they have the same identifier:

    image

    And, finally, structural equivalence means the complete equivalence of all fields of two objects:

    image

    The main difference between entities and value objects lies in the way we compare their instances with each other. The concept of equivalence of identifiers refers to entities, while structural equivalence refers to value objects . In other words, entities have an inherent identity, while value objects do not.

    In practice, this means that value objects do not have an identifier field, and if two instances of the same value object have the same set of attributes, we can consider them interchangeable. At the same time, even if the data in two entities are completely identical (with the exception of the Id field), they are not the same entity.

    You can think of it in the same way that you think of two people who have the same name. We do not consider them the same person because of this. They both have an internal (integral) identity. At the same time, if we have 1 ruble, we don’t care if it is the same coin that we had yesterday. So long as this coin is a coin with a value of 1 ruble, we do not mind replacing it with another one, exactly the same. The concept of money in this case is a value object.

    Life cycle


    Another difference between the two concepts is the life cycle of their instances. Entities live in a continuum. They have a story (even if we do not keep this story) of what happened to them and how they changed throughout life.

    Value objects, on the other hand, have a zero life cycle. We create and destroy them with ease. This is a consequence that follows logically from the fact that they are interchangeable. If the ruble coin is exactly the same as the other ruble coin, then what's the difference? We can simply replace the existing object with another instance and forget about it after that.

    Gaidlan, which follows from this difference, lies in the fact that value objects cannot exist on their own, they must always belong to one or more entities. Data, which is an object-value, have meaning only in the context of any entity. In the example with coins above, the question “How much money?” Does not make sense, because it does not carry sufficient context. On the other hand, the question “How much money does Petya have?” Or “How much money does all users of our system have?” Are completely valid.

    Another consequence here is that we do not store value objects separately. Instead, we should inline (attach) them to entities when saving to the database (more on that below).

    Immutability


    The next difference is immutability. Value objects must be immutable in the sense that if we need to change such an object, we create a new instance based on the existing one instead of changing the existing one. In contrast, entities are almost always mutable.

    Mandatory immutability of value objects is not accepted by all programmers. Some people think that this guideline is not as strict as the previous ones, and value objects can be mutable in some cases. I also held this opinion some time ago.

    Currently, I believe that the relationship between immutability and the ability to replace one value object with another lies deeper than I thought. By changing an instance of a value object, we mean that it has a non-zero life cycle. And this assumption, in turn, leads to the conclusion that value objects have an internal identity, which contradicts the definition of this concept.

    This simple mental exercise makes immutability an integral part of value objects. If we accept that they have a zero life cycle, in the sense that they are just a cast of a state and nothing more, then we must also accept that they can represent only one version of this state.

    This leads us to the following rule:if you cannot make the value object immutable, then this class is not a value object .

    How to recognize a value object in a domain model?


    It is not always clear whether a concept in a domain model is an entity or an object-value. And unfortunately, there are no objective attributes by which we could judge this. Whether or not a class is an object-value completely depends on the domain domain in which we operate: the same object can be modeled as an entity in one domain and as an object-value in another.

    In the example above, we view money as interchangeably interchangeable. Thus, this concept is a value object. At the same time, if we create a system for tracking all banknotes in the country, we need to consider each banknote separately to collect statistics on it. In this case, the concept of money will be the essence.

    Despite the lack of objective indicators, we can still use some techniques in order to attribute the concept to entities or value objects. We have already discussed three types of equivalence: if we can replace one instance of a class with another with the same properties, then this is a good sign that we have an object-value.

    A simpler version of the same trick is to mentally compare the class with an integer value (integer). It doesn't matter to you as a developer whether the number 5 is the same number that you used in the previous method. All fives in your application are the same, no matter how they were created. This makes the integer type essentially a value object. Now, ask yourself: does this class look like integer? If the answer is yes, then this is a value object.

    How to store value objects in a database?


    Suppose we have two classes in the domain model: the Person entity and the Address value object:

    // Entity
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Address Address { get; set; }
    }
    // Value Object
    public class Address
    {
        public string City { get; set; }
        public string ZipCode { get; set; }
    }
    

    What will the database structure look like in this case? The solution that comes to mind in this situation is to create separate tables for both classes:

    image

    Such a design, despite the full validity from the point of view of the database, has two drawbacks. First, the Address table contains an identifier. This means that we will need to enter a separate Id field in the Address class in order to work with such a table correctly. This, in turn, means that we add some identity to the class. And this already violates the definition of a value object.

    The second drawback here is that we can potentially separate the value object from the parent of the entity. Address can live its own life, as we can remove Person from the database without deleting the corresponding Address line. This will be a violation of another rule, which says that the lifetime of value objects should completely depend on the lifetime of their parent entities.

    The best solution in this case is to “inline” the fields from the Address table to the Person table:

    image

    This will solve both problems: Address will not have its own identifier and its lifetime will completely depend on the lifetime of the Person entity.

    This design also makes sense if you mentally replace all fields related to Address with a single integer, as I suggested earlier. Do you create a separate table for each integer value in your domain model? Of course not, you just include it in the parent table. The same rules apply to value objects. Do not create a separate table for value objects , just include their fields in the table of the entity to which they belong.

    Prefer value objects to entities


    The following rule is important in the matter of value objects and entities: always prefer value objects to entities. Value objects are immutable, and because of this, it is extremely easy to work with them. Ideally, you should always strive to incorporate most business logic into value objects. Entities in such situations will serve as wrappers over them and represent higher-level functionality.

    It may also happen that the concept that you originally saw as an entity is actually a value object. For example, you could initially represent the Address class in your code as an entity. It can have its own Id and a separate table in the database. After some thought, you notice that in your subject area the addresses do not actually have their own identity and can be used interchangeably. In this case, feel free to refactor your domain model, convert the entity into a value object.

    Conclusion


    • Entities have their own intrinsic identity. Value objects are not.
    • The concept of equivalence of identifiers refers to entities; the concept of structural equivalence refers to value objects; referential equivalence - to both.
    • Entities have a story; value objects have a zero life cycle.
    • The value object must always belong to one or more entities, it cannot live its own life.
    • Value objects must be immutable; entities are almost always mutable.
    • To recognize a value object, mentally replace it with an integer.
    • Value objects should not have their own table in the database.
    • Prefer value objects to entities when modeling a domain.

    English version of the article: Entity vs Value Object (DDD)

    Also popular now: