Entity vs Value Object: the ultimate list of differences

The topic described in this article is a part of my Domain-Driven Design in Practice Pluralsight course.

I wrote about entities and value objects some time ago. In this post, I’d like to talk about differences between Entity vs Value Object in more detail.

I know, the topic isn’t new and there are a lot of articles on the Internet discussing it already. Nevertheless, I didn’t find any with an exhaustive, comprehensive description, so I decided to create my own.

1. Entity vs Value Object: types of equality

To define the differences between entities and value objects, we need to introduce three types of equality which come into play when we need to compare objects to each other.

Reference equality means that two objects are deemed to be equal if they reference the same address in the memory:

Reference equality
Reference equality

Here’s how we can check that in code:

object object1 = new object();
object object2 = object1;
bool areEqual = object.ReferenceEquals(object1, object2); // returns true

Identifier equality implies a class has an id field. Two instances of such a class would be equal if they have the same identifiers:

Identifier equality
Identifier equality

And finally, with structural equality, we consider two objects equal if all of their members match:

Structural equality
Structural equality

The main difference between entities and value objects lies in the way we compare their instances to each other. The concept of identifier equality refers to entities, whereas the concept of structural equality - to value objects. In other words, entities possess inherent identity while value objects don’t.

In practice it means that value objects don’t have an identifier field and if two value objects have the same set of attributes we can treat them interchangeably. At the same time, if data in two entity instances is the same (except for the Id property), we don’t deem them as equivalent.

You can think of it in a similar way you would think of two people bearing the same name. You don’t treat them as the same person because of that. Both of the people have their own inherent identity. Yet, if a person has a 1 dollar bill, they don’t care if this physical piece of paper is the same as they had yesterday. Until it’s still 1 dollar, they are fine with replacing this note with another one. The concept of money in such case would be a value object.

2. Entity vs Value Object: lifespan

Another distinction between the two notions is the lifespan of their instances. Entities live in continuum, so to speak. They have a history (even if we don’t store it) of what happened to them and how they changed during their lifetime.

Value objects, at the same time, have a zero lifespan. We create and destroy them with ease. That’s a corollary of being interchangeable. If this 1 dollar bill is the same as another one, why bother? We can just replace the existing object with the one we just instantiated and forget about it altogether.

A guideline that flows from this distinction is that value objects cannot live by their own, they should always belong to one or several entities. The data a value object represents has a meaning only in the context of an entity it refers to. In the example above with people and money, the question "How much money?" doesn’t make any sense because it doesn’t convey proper context. At the same time, questions "How much money Peter has?" or "How much money all our users possess?" are perfectly valid.

Another corollary here is that we don’t store value objects separately. The only way for us to persist a value object is to attach it to an entity (more about it in a minute).

3. Entity vs Value Object: immutability

The next difference is immutability. Value objects should be immutable in a sense that if we need to change such an object, we construct a new instance based on the existing object rather than changing it. On the contrary, entities are almost always mutable.

The question whether or not value objects should always be immutable is a subject of a dispute. Some programmers argue that this rule is not as strict as the previous one, and value objects can indeed be mutable in some cases. I used to adhere to this point of view as well.

Nowadays, I find the connection between immutability and the ability to replace a value object with another one is deeper that I thought. By mutating an instance of a value object, you assume it has its own life cycle. And that assumption, in turn, leads to a conclusion that the value object has its own inherent identity, which contradicts the definition of that DDD notion.

This simple mental exercise makes immutability an intrinsic part of Value Object. If we accept value objects have a zero lifetime, meaning that they are just snapshots of some state and nothing more, then we have to admit they are allowed to represent only a single variant of that state.

That leads us to the following rule of thumb: if you can’t make a value object immutable, then it is not a value object.

4. How to recognize a value object in your domain model?

It’s not always clear if a concept in your domain model is an entity or a value object. And unfortunately, there are no objective attributes you could use to get to know it. Whether or not a notion is a value object fully depends on the problem domain: a concept can be an entity in one domain model and a value object in another.

In the example above, we treat money interchangeably, which makes this concept a value object. At the same time, if we build a software for tracking cash flow in the entire country, we would need to treat every single bill separately to gather statistics for each of them. In this case, the notion of money would be an entity, although we would probably name it Note or Bill.

Despite the lack of objective traits, you can still employ some technique in order to attribute a concept to either entities or value objects. We discussed the notion of identity: if you can safely replace an instance of a class with another one which has the same set of attributes, that’s a good sign this concept is a value object.

A simpler version of that technique is to compare a value object to an integer. Do you really care if the integer 5 is the same 5 that you used in another method? Definitely not, all fives in your application are the same regardless of how they were instantiated. That makes an integer essentially a value object. Now, ask yourself, is this notion in your domain looks like integer? If the answer is yes, then it’s a value object.

5. How to store value objects in the database?

Let’s say we have two classes in our domain model: Person entity and 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; }
}

How would the database structure look like in this case? One option that comes to mind is to create separate tables for each of them, like this:

Storing the value object in a separate table
Storing the value object in a separate table

Such design, albeit being perfectly valid from the database standpoint, has two major drawbacks. First of all, the Address table contains an identifier. It means that we will have to introduce a separate Id field in the Address value object to work with such table correctly. This, in turn, means we are providing the Address class with some identity. And that violates the definition of Value Object.

The other drawback is that with this solution, we can potentially detach value objects from entities. The Address value object can now live by its own because we are able to delete a Person row from the database without deleting the corresponding Address row. That would violate another rule which states that the lifetime of value objects should fully depend on the lifetime of their parent entities.

It turns out that the best solution is to inline the fields from the Address table into the Person table, like this:

Inlining the value object
Inlining the value object

This would solve all the problems I stated earlier: Address doesn’t have an identity anymore and its lifetime now fully depends on the lifetime of the Person entity.

This design also makes sense if you mentally replace the fields that regard to Address with a single integer as I suggested previously. Do you create a separate table for an integer? Of course not, you just inline that integer to the table you want it to be in. The same applies to the value objects. Don’t introduce separate tables for value objects, just inline them into the parent entity’s table.

6. Prefer value objects over entities

When it comes to working with entities and value objects, an important guideline comes into play: always prefer value objects over entities. Value objects are immutable and more lightweight than entities. Because of that, they are extremely easy to work with. Ideally, you should always put most of the business logic into value objects. Entities in this situation would act as wrappers upon them and represent more high-level functionality.

Also, it might be that a concept you saw as an entity at first essentially is a value object. For example, the Address class in your code base could be introduced as an entity initially. It may have its own Id field and a separate table in the database. After revisiting it, you might notice that in your domain, addresses don’t actually have their own inherent identity and can be used interchangeably. In this case, don’t hesitate to refactor your domain model and convert the entity into a value object.

7. Summary

Alright, I think I covered every aspect that regards to the topic of Entity vs Value Object. Let’s summarize it with the following:

  • Entities have their own intrinsic identity, value objects don’t.

  • The notion of identity equality refers to entities; the notion of structural equality refers to value objects; the notion of reference equality refers to both.

  • Entities have a history; value objects have a zero lifespan.

  • A value object should always belong to one or several entities, it can’t live by its own.

  • Value objects should be immutable; entities are almost always mutable.

  • To recognize a value object in your domain model, mentally replace it with an integer.

  • Value objects shouldn’t have their own tables in the database.

  • Always prefer value objects over entities in your domain model.

Subscribe


I don't post everything on my blog. Don't miss smaller tips and updates. Sign up to my mailing list below.

Comments


comments powered by Disqus