Nesting a Value Object inside an Entity



In this post, we are going to look at what to do if you are not able to treat some concept in your domain as a Value Object and have to make it an Entity. TL;DR: create a nested Value Object inside that Entity and relocate as much domain logic to that Value Object as possible.

Nesting a Value Object inside an Entity

In the last post, we discussed how to represent a collection of Value Objects as a Value Object itself. The solution is to make it obey the same rules as other Value Objects: define structural equality, make sure it is immutable and serialize the whole collection into a string when persisting it to a data store.

However, because of the last serialization part, that solution is sub-optimal if you need to perform a search among those Value Objects using standard database features. It is also not the best implementation if the number of items in the collection is too high as it might cause performance issues.

In this case, you don’t have any choice other than persisting such value objects in a separate table. This entails the necessity to deal with the identifiers assigned to them on the database level, and that essentially means treating items in the collection as Entities.

Let’s take the example from the previous post. Here’s the City value object:

public sealed class City : ValueObject<City>

{

    public string Name { get; }

    public bool IsEnabled { get; }

 

    public City(string name, bool isEnabled)

    {

        Name = name;

        IsEnabled = isEnabled;

    }

 

    protected override bool EqualsCore(City other)

    {

        return Name == other.Name && IsEnabled == other.IsEnabled;

    }

 

    protected override int GetHashCodeCore()

    {

        return Name.GetHashCode() ^ IsEnabled.GetHashCode();

    }

}

There also is a User entity which holds a collection of cities. Let’s say that each user might have hundreds of those cities and it is not practical – due to performance reasons – to serialize them into a string every time you persist a user. In this case, you have to create a separate table for City:

Nesting a Value Object inside an Entity: City entity

City entity

And, as a result, you need to convert the City class from a Value Object into an Entity:

public class City : Entity

{

    // Id is in the Entity base class

    public string Name { get; protected set; }

    public bool IsEnabled { get; protected set; }

    public User User { get; protected set; }

 

    public City(string name, bool isEnabled, User user)

    {

        Name = name;

        IsEnabled = isEnabled;

        User = user;

    }

}

This solves the problem with performance, but now we’ve complicated the model. Instead of just a single entity – User entity – we now have two of them. And the City entity clearly has a Value Object semantics: we don’t care about its identity and we don’t mind to replace one with another as long as their names match.

Is there a way to mitigate that issue?

Luckily, yes. There is a compromise solution. You can extract a value object out of City and transfer all business logic the entity possesses to it. The entity, in this case, will act as a thin wrapper on top of that value object with just an identifier and a reference to the corresponding user. The resulting value object, at the same time, will have the same structure as before:

internal class CityInUser : Entity

{

    public City City { get; protected set; }

    public User User { get; protected set; }

 

    public CityInUser(City city, User user)

    {

        City = city;

        User = user;

    }

}

 

public sealed class City : ValueObject<City>

{

    public string Name { get; }

    public bool IsEnabled { get; }

 

    /* … */

}

Note that I renamed the entity to CityInUser so that there’s no collision in names between the two classes. Also note that I made it internal. The best part in this approach is that although you do have an additional entity in your domain model, you don’t ever have to expose it outside of the aggregate. The client code that works with User doesn’t have to be aware of that auxiliary entity and can work with the City value object directly.

For example, here’s how User might expose the collection of cities and addition of new items to it:

public class User : Entity

{

    private IList<CityInUser> _cities;

 

    public IReadOnlyList<City> Cities =>

        _cities

            .Select(x => x.City)

            .ToList();

 

    public void AddCity(City city)

    {

        _cities.Add(new CityInUser(city, this));

    }

}

As you can see, both methods expose value objects and perform the necessary conversions internally making the life of the client code easier.

Nesting a Value Object inside an Entity: examples

It’s important to keep the wrapping entity as shallow as possible. That will help you adhere to the “Value Objects over Entities” guideline, and will provide a nice separation of concerns: the entity, in this case, will be responsible for “technical stuff”, such as holding an identity imposed by the database, while the value object will contain the domain logic.

Let’s take some more examples of where this approach is applicable.

Some time ago, I needed to create an Organization class and assign a collection of emails to it. Treating that collection as a value object wouldn’t fit the requirements because I had to ensure the emails’ uniqueness on the database level. So the only way to proceed with the task was to introduce a separate table for organizations’ emails:

Nesting a Value Object inside an Entity: Email value object

Email value object

Emails themselves here are clearly value objects. Fortunately, we can still treat them as such if we apply the approach I described earlier:

public class Organization : Entity

{

    private IList<OrganizationEmail> _emails;

 

    public IReadOnlyList<Email> Emails =>

        _emails

            .Select(x => x.Email)

            .ToList();

 

    public void AddEmail(Email email)

    {

        _emails.Add(new OrganizationEmail(email, this));

    }

}

All business logic can be placed into Email the value object, thus providing all the benefits of dealing with value objects as opposed to entities.

Another example is the well-known OrderLine sample. This problem doesn’t quite fit the narrative I’m following here but has a similar solution. So, here’s the code:

public class Order

{

    private IList<OrderLine> Lines { get; set; }

}

 

public class OrderLine

{

    public int Position { get; set; }

    public Order Order { get; private set; }

    public int Quantity { get; private set; }

    public Product Product { get; private set; }

    public decimal Price { get; private set; }

}

The Order class it clearly an entity. Moreover, it’s an aggregate root. As for OrderLine, it might seem uncertain what it is. On one hand, we want to treat lines in an order interchangeably but on the other, we still want to mutate their position – order lines are not entirely immutable here.

This dichotomy is false, however, because what we have is two concepts that include one another. The OrderLine class itself is an entity: it’s mutable and has an identity local to its aggregate which is defined by its Position property. At the same time, the three fields in it – Quantity, Product, and Price – do comprise a value object, a conceptual whole which doesn’t possess an identity of any kind and which can be deemed replaceable.

The solution to this problem is the same as to the previous one: implement OrderLine as an entity and introduce a nested value object.

public class Order : Entity

{

    private IList<LineInOrder> _lines;

 

    public IReadOnlyList<OrderLine> Lines =>

        _lines

            .OrderBy(x => x.Position)

            .Select(x => x.Line)

            .ToList();

}

 

internal class LineInOrder : Entity

{

    public int Position { get; set; }

    public Order Order { get; private set; }

    public OrderLine Line { get; private set; }

}

 

public sealed class OrderLine : ValueObject<OrderLine>

{

    public int Quantity { get; }

    public Product Product { get; }

    public decimal Price { get; }

}

Once again, we are able to hide the entity by making it internal and exposing only the value object to the outside world. And that value object is capable of keeping all business logic that belongs to a line. The only difficulty here is that we have to come up with a made-up name for that entity to avoid collision with the value object.

Here’s a fully-fledged example of an analogous problem from my DDD in Practice Pluralsight course: Slot entity and SnackPile value object.

Summary

Nesting a value object into an entity is a powerful technique that can help you bring your code closer to the “Value Objects over Entities” guideline. It is applicable when treating some concept in your domain model as Value Object is not a feasible task due to limitations imposed by your database.

To implement it in practice, make sure you:

  • Keep the wrapping entity thin. It should only hold the identity imposed by the database.
  • Transfer all domain logic from that entity to the nested value object.
  • Don’t expose the entity outside the aggregate. Clients of the aggregate should work directly with the value object.

Related articles:

Share




  • Michael G.

    Great article. I hadn’t considered to use a wrapper in such a fashion, but now that I’ve read it, it makes sense to do so, rather than treat the entire object as an Entity.

    How does this translate to relations with composite keys?
    Considering a permission system for a forum, there are usually Groups and Members, each with a set of Permissions.

    Permissions
    MemberId
    GroupId
    ForumId
    CanCreatePost
    CanEditPost
    CanDeletePost

    The Permissions (ForumId + CanX) are clearly a ValueObject, which applies to a combination of MemberId and GroupId, with either of those being nullable, but not both.

    Considering that a Member can belong to one or more Groups, would it still be feasible to use the entity wrapper?

    PS: I consider ForumId part of the Permission ValueObject in this context, since it doesn’t identify a single Permission, but is merely data.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Considering that a Member can belong to one or more Groups, would it still be feasible to use the entity wrapper?

      I don’t see why not. You could gather those permissions and expose them as a single collection of value objects. A good part here is that you can implement some sophisticated merge logic, for example squash 3 permissions with different CanX under a single one, and the client code doesn’t have to deal with it on its own.

      • Michael G.

        Great! Now I just need to figure out how to do so, while maintaining proper separation of concerns. But that is a self-educational task 🙂

        More and more I find myself using ValueObjects in code, and it is, so far, much easier to maintain and understand than bloated Entities.

        Thank you for the constant stream of useful articles on the subject.

  • E.

    Thanks for your excellent explanation and good timing because I’m struggling with a related problem.
    In my case I have and Address that is related to Person and Company.
    In both relations I need to keep track of the history (DateFrom and DateTo) for the possible changing address locations.
    In my model, I need one unique addressId for each period in time.
    Is it advisable to use Address as an entity with AddressDetail as value object?
    And in the corresponding History tables I use AddressDetail and DateRange as value objects?
    Or do you have a better approach?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Yes, this implementation looks good, especially if you are able to hide the entity that is responsible for the history, so that the client code doesn’t see it. Also, try to unify the history and the address entities by nesting the AddressDetail value object in both of them.

      So, in Person or Company, you can have a CurrentAddress property that returns the AddressDetail value object, and you also can introduce a GetAddressRecord method that would accept a date, search among the history entities and also return an AddressDetail.

      DateRange as a separate value objects is almost always a good design decision.

  • http://buclenet.com Albert Capdevila

    Excellent! Thanks!

  • Kirk

    I realise this post is over a year old now so I was wondering what your opinion might be for using an “IdentifiableValueObject” abstract class to solve such cases as described above? This way we can keep the Value Object semantics that we’re striving for and remove the requirement to create a lot of nested value objects. By using FluentNHibernate’s Reveal functionality we can also make the Id protected and therefore keep it hidden from any client code making it look and behave like a Value Object.

    For example;

    public abstract class IdentifiableValueObject
    : ValueObject where T : ValueObject
    {
    protected virtual long Id { get; set; }
    }

    public class ValueObjectWithIdentity :
    IdentifiableValueObject
    {
    public virtual string Identifier { get; protected set; }

    protected override bool EqualsCore(ValueObjectWithIdentity other)
    {
    return Identifier == other.Identifier;
    }

    protected override int GetHashCodeCore()
    {
    return Identifier.GetHashCode();
    }
    }

    public class ValueObjectWithIdentityMap : ClassMap
    {
    public ValueObjectWithIdentityMap()
    {
    Id(Reveal.Member(“Id”));
    }
    }

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Would be interesting to try this in practice. I’m not sure how the ORM will react to this, though, a proof of concept is needed.

  • Mher Sargsyan

    Hi Vladimir,

    Thanks for perfect explanation. However there is still a question regarding the equals and hashcode methods. I guess in case of local entity LineInOrder int position will be used. What about the CityInUser as there is no “conceptual” identity in this case. Is that ok to rely on persistence id ?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      There shouldn’t be such an issue as you don’t expose CityInUser to the clients of the class, all User’s members (properties and methods) should work with City instead, and therefore compare them by their structure.

      Internally (within the User class), it’s OK to rely on DB Id but that also should be used mostly for O/R mapping only.

  • Mher Sargsyan

    Hi Vladimir,

    Firstly I want to thank you for a great advise not to fight a relational database. Indeed it helped me a lot to put everything together and come up with a working model for one of my sub-domains. So the solution with Order -> LineInOrder -> OrderLine worked perfectly. (In my case actually we call them PartInOrder -> OrderPart, but that’s just because of our ubiquitous language:) ).

    However there is one more dilemma I am facing. Most probably this will span multiple topics (at least partially https://enterprisecraftsmanship.com/2016/03/08/link-to-an-aggregate-reference-or-id/).

    So here is the thing.

    After successfully getting to a working aggregate where Order acts as a root, PartInORder as an entity local to aggregate and OrderPart as a VO
    I got a new requirement to implement a feature which will allow OrderParts to be copied to new entities called Production Job. In order to make it clear I am not dealing with e-commerce domain but with an e-fulfillment and Production Jobs represent producible copies of orderParts with different lifespan and life cycle.

    In order to extend the system with this new feature I designed a new aggregate called job where ProductionJob acts as the root. (Modeling jobs as entities local to Order is not an option as there are no consistency requirements, jobs have completely different life cycle and also it will make orders aggregate too big causing performance and concurrency issues). So long story short. Everything goes as expected except the part where I need to keep a connection between a Job and an OrderPart. From one perspective it will be really nice to create a Job by passing a reference to PartInOrder (reminder this is an entity local to aggregate) and having an ORM to take care or the rest (storing a job with FK to partinorder, however in my case I have OGM backed by neo4j graph database but this is not an issue and in this case relation will be represented by an edge in a graph). However in this case I will brake the rule of referring to an aggregate by it’s root only.

    The other solution is to have a collection of Jobs in OrderPart value object and after creating an instance of ProductionJob I will add it to orderPart.jobs and persist the whole order which will cascade to parts and newly added jobs. In this case I will end up with a situation when a transaction spans multiple (orders, jobs) aggregates.

    So the question is which rule I am going to break ?? 🙂

    Sorry for a long story and thanks in advance.
    Regards, Mher.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Great to hear it was a good fit for your domain!

      This is an interesting challenge. I wouldn’t recommend having jobs as a collection in OrderPart, the cost of this decision is too high (too big aggregates).

      Regarding the first option of passing a reference of PartInOrder to Job. It looks like there should be another solution. Could you elaborate why you need a connection between Job and OrderPart and what part of this class Job needs to know about?

      • Mher Sargsyan

        Hi Vladimir,

        During last few days I spent time on rethinking the design of orders aggregate as well as talking to domain experts and analyzing requirements.

        So firstly, it seems like the solution I have at this moment with Order -> OrderParts needs to be modified. The conceptual difference between domain experts point of view and my technical solution is that when they say “order part” it’s not something conceptually different from the root “order”. After talking to them for a while I realized that even a single ProductionOrder can exist in space and time )). So when they say “order part” that just means we are dealing with a “complex” production order which consists of a root and multiple parts.

        After analyzing additional requirements that we are going to work on short to mid term I came to a conclusion that we are going to deal with trees of orders not just structures order -> orderParts. After this observation I came up with a new abstraction called ProductionManifest which is responsible for production invariants (obviously this is a VO). After having these two ideas the complete redesign of orders aggregate would be something like AggregateRoot ProductionOrder which can have a reference to Collection. And according to domain experts every element in a tree can have/not have ProductionDetails. It’s worth to mention that domain experts were able to provide examples of such orders (Obviously I missed this part during initial knowledge gathering process:))).

        So in the end when I have ProductionDetails as a new conceptual hole I can answer the question “why I want to keep a reference between JOb and Order PArt”.

        So:

        1. If the design will be like ProductionOrder -> childOrders the issue with referring to Orders aggregate via non root will disappear.
        2. Why exactly I wanna keep the reference? This is a really good question as after having ProductionDetails I can simply copy to jobs which I in fact do. THe only reason for keeping the reference is for using ORM to build a relation in the database as after (as I am using CQRS) I am going to query orders and calculate their status based on statuses of associated jobs. So this is the only reason. To build a relation. Other than this copying ProductionDetails is more than enough for order managers to access everything they need. Which means when I retrieve an instance of Job aggregate it’s not mandatory to hidrate it to have ProductionOrder in it.