Value Objects: Entity Framework vs NHibernate



In this post, I’d like to discuss how Entity Framework and NHibernate allow us to deal with mapping of Value Objects in our domain models.

Value Objects

Just a quick refresher regarding what a value object is. Value Object is a design pattern introduced by Eric Evans in his DDD book. It stands for concepts in your domain model which don’t have their own inherent identity. Because of that, they are immutable and have a zero lifespan. When it comes to saving value objects into a data store, the data that belongs to them should be inlined into the entities’ tables. To read more about Value Object and how it differs from Entity, check out this article: Entity vs Value Object: the ultimate list of differences.

Value Objects in Entity Framework

Entity Framework has made a great progress since the Code First functionality was introduced. A domain model mapped using Entity Framework no longer has to be in a 1-to-1 relationship with the underlying database structure. Part of this progress was a better support for value objects. You can represent them using the Complex Type feature, like this:

public class Customer // Entity

{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

}

public class Address // Value Object

{

    public string Street { get; set; }

    public string City { get; set; }

}

public class Context : DbContext

{

    public DbSet<Customer> Customers { get; set; }

 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)

    {

        modelBuilder.ComplexType<Address>();

    }

}

The Street and City fields will be inlined into the Customer table after that, just as you would expect from a value object:

Value Objects Entity Framework NHibernate: Value Objects in Entity Framework

Value Objects in Entity Framework

Although this functionality looks promising, there are 2 major use cases which are not supported by Entity Framework.

The first one is references from value objects to entities. If for example, addresses in your domain model refer to a country, you can’t depict this relationship as follows:

public class Customer // Entity

{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

}

 

public class Address // Value Object

{

    public string Street { get; set; }

    public string City { get; set; }

    public Country Country { get; set; } // Not supported

}

 

public class Country // Entity

{

    public int Id { get; protected set; }

    public string Name { get; protected set; }

}

What you have to do instead is you need to use an Id instead of the actual reference (navigation property in the EF’s terminology):

public class Address

{

    public string Street { get; set; }

    public string City { get; set; }

    public int CountryId { get; set; }

}

While this workaround allows us to overcome the technical limitation, it comes at a price. Direct use of Ids in your entities and value objects means poor separation of concerns. The principle of Persistence Ignorance tells us that our classes shouldn’t be affected by how they are stored in the database. The necessity to represent a link to a country with an identifier means we are mixing the domain model design with the persistence concerns.

Note that this is true only when a value object refers to an entity. EF does handle a situation where a value object contains another value object.

Another issue with value objects in EF is that Entity Framework doesn’t handle their nullability well. If for example, you say that a customer may or may not have an address, you can’t just consider this field nullable:

public class Customer

{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

 

    public Customer(int id, string name)

        : this()

    {

        Id = id;

        Name = name;

        Address = null; // Can’t do that

    }

}

You need to always put something there. In other words, you need to always come up with a Null Object and use it in place of nulls. In some cases, you do have such an object in your domain model, but in many situations, you don’t. And if the latter is the case, you have to artificially modify your domain classes in order to comply with this EF requirement.

So, in our case, we need to do the following:

public class Customer

{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

 

    public Customer(int id, string name)

        : this()

    {

        Id = id;

        Name = name;

        Address = new Address(null, null, null);

    }

}

 

public class Address

{

    public string Street { get; set; }

    public string City { get; set; }

    public int? CountryId { get; set; }

 

    public bool IsNull

    {

        get { return Street == null && City == null && CountryId == null; }

    }

 

    public Address(string street, string city, int? countryId)

        : this()

    {

        Street = street;

        City = city;

        CountryId = countryId;

    }

}

Note that we had to make the Address.CountryId property nullable. The problem here is that your value objects may have their own invariants and a requirement to always have a country assigned to an address can be one of them. With this approach, we are unable to represent such invariants. This means that we once again damaged the domain model isolation. At this time, by coupling the domain classes to the ORM’s concerns.

Value Objects in NHibernate

With NHibernate, you don’t have such limitations. You can easily define value objects that refer to entities:

public class Customer // Entity

{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

}

 

public class Address // Value Object

{

    public string Street { get; set; }

    public string City { get; set; }

    public Country Country { get; set; }

}

public class CustomerMap : ClassMap<Customer>

{

    public CustomerMap()

    {

        Id(x => x.Id);

        Map(x => x.Name);

 

        Component(x => x.Address, y =>

        {

            y.Map(x => x.Street);

            y.Map(x => x.City);

            y.References(x => x.Country);

        });

    }

}

Note that I’m using the Component mapping feature of NHibernate. It is also possible to map a value object by creating a custom type that inherits from the NHibernate’s IUserType. I don’t recommend this approach, though. Such a type will have functionality that doesn’t belong to your domain model which means this type won’t be a POCO. The Component feature works exactly how you would want it to with regards to value objects.

With NHibernate, it is also possible to have nullable value objects. You can write code like this:

public class Customer

{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

 

    public Customer(int id, string name)

    {

        Id = id;

        Name = name;

        Address = null;

    }

}

// Usage example

var customer = new Customer(1, “New Customer”);

SaveCustomer(customer);

And all fields that relate to the value object will be transformed into NULLs on saving the customer to the database:

Value Objects Entity Framework NHibernate: NHibernate handles nullable Value Objects

NHibernate handles nullable Value Objects

When reading value objects from the data store, NHibernate applies a convention. If all columns that regard to a value object are NULLs, then the value object itself is null. If any of the fields have a non-NULL value, NHibernate instantiates a value object and fills all its properties except for the non-nullable one with nulls.

This way, you are able to preserve the invariants of your domain classes. In our case, we are able to explicitly specify that all fields of the Address class are required even if the Customer.Address property itself can turn into null. We don’t have to sacrifice the domain model integrity:

public class Address // Value Object

{

    public string Street { get; set; }

    public string City { get; set; }

    public Country Country { get; set; }

 

    public Address(string street, string city, Country country)

    {

        if (street == null) throw new ArgumentNullException(nameof(street));

        if (city == null) throw new ArgumentNullException(nameof(city));

        if (country == null) throw new ArgumentNullException(nameof(country));

 

        Street = street;

        City = city;

        Country = country;

    }

}

Value Objects in Entity Framework and NHibernate: results

The limitations Entity Framework imposes on the use of value objects make it harder to incorporate them into your domain model. These restrictions may become a big hurdle down the road, when you progress with you application’s design.

Of course, there always is a workaround: not using complex value objects at all. But I don’t think it’s a good solution either as value objects are a great tool when it comes to building an expressive domain model. Forgoing this tool just because of the limitations an ORM imposes isn’t the best strategy, especially taking into account there is a good alternative to EF on the market.

Summary

  • Entity Framework has two limitations when it comes to using value objects in your domain model.
    • Value objects can’t refer to entities
    • A value object property in an entity cannot be null
  • These limitations lead to inability to build an isolated domain model
  • NHibernate doesn’t have such limitations

Related articles:

Share




  • Miguel Bruno Gouveia

    Did you not forgot to mention one another hypothesis to resolve the problem with the Entity Framework?
    We can use data access objects (DAOs) in the data base layer that them are mapped to the domain objects. In this manner the value objects are fully supported. The disadvantage is that we need to implement and maintain the mapping code. But is still an option.

    • Flynn

      My thoughts exactly. I wouldn’t map my Domainobjects directly to the database. I would use AutoMapper for example. That should give me all the flexibility I need.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Good point! Indeed, it may be another workaround.

      I personally think it is too much of a hurdle to build and maintain a own mapping layer, though, especially for complex domain models, but that’s another topic. I will probably blog about it soon.

    • youzer

      DAO’s FTW! I stopped mapping domain objects directly to ORM frameworks. I don’t care about the extra effort if it means that I have compete insight into how my domain objects interact with a persistence mechanism. Too much overhead to consider with EF, that’s for sure.

  • forwardisstilltheonlyway

    In the example above, why does the Address need to be a seperate object? In every project I’ve worked in so far the best solution is a 1-1 domain model to db tables.
    In another post you mention people coming up with complex solutions to simple problems, I tend to think that’s what has been done here.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      You mean why Address needs to be a Value Object instead of an Entity? Whether or not some concept is a value object depends on the domain model. In some domain it may be an entity, in another – a value object. Here I wrote about that in more detail: http://enterprisecraftsmanship.com/2016/01/11/entity-vs-value-object-the-ultimate-list-of-differences/

      Regarding simplicity, 1-to-1 correspondence between the domain model and the database doesn’t necessarily mean a simpler solution. Yes, the mapping itself tends to be simpler (at least in EF), but value objects are generally easier to work with due to their immutability. Because of that, a design with less entities tends to be simpler.

  • Jean Pierre Chauny

    Nice article.
    What are your thoughts about Value Objects Inheritance Hierarchies?
    Because of the immutability of Value Objects they are easy to reason about. They can also be part of the immutable core in an immutable architecture from the perspective of functional programming. Due to this properties I have read recommendations of pushing the complex domain logic as much as possible into Value Objects.
    Are Value Object Inheritance Hierarchies a good idea?
    What problems arise when mapping these Value Objects Hierarchies using ORM like EF and NHibernate?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Due to this properties I have read recommendations of pushing the complex domain logic as much as possible into Value Objects.

      Absolutely. Making Value Objects part of the immutable core and pushing as much logic as possible to them is always a good idea because Value Objects are light-weight and easy to work with. You might want to also check out this article on that subject: http://enterprisecraftsmanship.com/2016/01/11/entity-vs-value-object-the-ultimate-list-of-differences/

      Regarding inheritance, there’s nothing wrong in inheriting one Value Object from another as long as this inheritance represents the domain model. Both EF and NHibernate support it. Beware of utility inheritance, though, the one that doesn’t reflect the actual relationship of the domain classes. Here I wrote about it in more detail: http://enterprisecraftsmanship.com/2015/09/11/dry-revisited/

  • Stephan Galea

    How exactly did you migrate that in nhibernate without errors?
    (without Country mapping) An association from the table [dbo].[Customer] refers to an unmapped class: Country
    (With Country mapping) {“There is already an object named ‘Country’ in the database.”}

    Can you post the country mapping too?

  • Jean Pierre Chauny

    Readonly properties were introduced in c# 6. I think this is the best way to define immutable value objects. But I ran into the problem of not being able to map this read only properties to the database using entity framework for persistence. I am missing something? In nHibernate this is possible as you show in your pluralsight course “Ddd in practice”. This limitation is really a shop stopper for EF in my opinion.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      No, you don’t miss anything. In EF, you have to have at least a protected setter for all properties in order to use them in mappings. That is a corollary from a (really bad, IMO) decision the EF authors made in the very beginning – they decided not to support mapping to private fields (Case #3 here: http://enterprisecraftsmanship.com/2014/11/29/entity-framework-6-7-vs-nhibernate-4-ddd-perspective/ ).

      Read-only properties compile to a read-only field wrapped by a property with a getter, so EF can’t support them. In NH, it is possible to use class fields in mappings, so this new C# 6 feature works without additional intervention.

  • Ali Reza Hossini