3 ways to avoid an anemic domain model in EF Core

Anemic (anaemic) domain models are extremely common when using ORM's such as Entity Framework. This post looks at the problems of having an anemic domain model and then goes on to look at a few simple techniques to allow you to create richer models when using Entity Framework Code First and EF Core.

What is an anemic domain model?

An anemic domain model is where you go to the trouble of modeling your domain as a set of classes but those classes contain no business logic. Instead the classes are simply data holders and when using Entity Framework they often consist of little more than a bunch of public getters and setters:

public class BlogPost { public int Id { get; set; } [Required] [StringLength(250)] public string Title { get; set; } [Required] [StringLength(500)] public string Summary { get; set; } [Required] public string Body { get; set; } public DateTime DateAdded { get; set; } public DateTime? DatePublished { get; set; } public BlogPostStatus Status { get; set; } ... }

Anemic domain models are often described as an anti-pattern due to a complete lack of OO principles. They are dumb objects relying on calling code for validation and other business logic. This lack of abstraction can often lead to code repetition, poor data integrity and increased complexity in higher layers. Anemic domain models are extremely common. From my experience (consulting for dozens of companies), I would estimate that more than 80% of EF domain models are anemic. This is hardly surprising. Practically all documentation and other blog articles demonstrate EF at its simplest. They are focused on getting you started as quickly as possible rather than advocating best practices (which may require slightly more work to set up initially).

Moving to a richer domain model

We are going to discuss three easy techniques to enrich your anemic domain models. These are very simple changes that can be adopted with minimal effort:

Remove public parameterless constructors

Unless you specify a constructor, your class will have a default parameterless constructor. This means that you can instantiate your class in the following way:

var blogPost = new BlogPost();

In most situations this makes no sense. Domain objects will typically require at least some data to make them valid. Creating a BlogPost instance without any data such as title or URL is meaningless. Without some useful data for identification, there is no point in allowing such an instance. Some people disagree but the prevailing belief in the DDD community is that it makes sense to ensure that domain objects are always valid. To help with this, we can treat our domain class just like any other OO class and introduce a parameterised constructor:

public BlogPost(string title, string summary, string body) { if (string.IsNullOrWhiteSpace(title)) { throw new ArgumentException("Title is required"); } ... Title = title; Summary = summary; Body = body; DateAdded = DateTime.UtcNow; }

Now calling code must provide a minimum of data to satisfy the contract (the constructor). This change provides two positive outcomes:

Any newly instantiated BlogPost object is now guaranteed to be valid. Any code acting on the BlogPost does not need to check for invalid values. The domain object validates itself automatically on instantiation. Any calling code knows exactly what is required to instantiate the object. With a parameterless constructor, this is unknown and it is very easy to build an object with missing data.

Unfortunately, after making this change, you will find that your EF code no longer works when retrieving entities from the database:

InvalidOperationException: A parameterless constructor was not found on entity type 'BlogPost'. In order to create an instance of 'BlogPost' EF requires that a parameterless constructor be declared.

EF requires a parameterless constructor for querying so what to do? Fortunately, while EF does require the parameterless constructor, it need not be public so we can add a private parameterless constructor for EF while forcing calling code to use the parameterised one. Having the additional constructor is obviously not ideal but these kind of compromises are often required to get ORMs to play nicely with OO code.

private BlogPost() { // just for EF } public BlogPost(string title, string summary, string body) { ... }

Remove public property setters

The parameterised constructor introduced above ensures that when instantiated, the object is in a valid state. This does nothing to prevent you from changing property values to invalid values later though. To fix this issue, we have two options:

Add validation logic to the property setters Prevent direct modification of properties and instead use methods corresponding to user actions

Adding validation to the property setter is perfectly acceptable but does mean that we can no longer use Automatic Properties and must introduce a backing field. Obviously this is not a big deal:

private string title; public string Title { get { return title; } set { if (string.IsNullOrWhiteSpace(value)) { throw new ArgumentException("Title must contain a value"); } title = value; } }

The main reason why option two is preferred is that it more closely models what happens in the real-world. Rather than updating a single property in isolation, users tend to perform a set of known actions (determined by the UI or API interface). These actions can result in one or more properties being updated but there is often more to it that that. It is very common to have scenarios where business logic is dependent upon context which can make property setter validation logic complex and hard to understand. As a basic example, consider the following blog post publication process:

public void Publish() { if (Status == BlogPostStatus.Draft || Status == BlogPostStatus.Archived) { if (Status == BlogPostStatus.Draft) { DatePublished = DateTime.UtcNow; } Status = BlogPostStatus.Published; } }

In this example, we have a publish method with some simple logic and two property that can be updated. We could also implement this as a property setter but it is far less clear, particularly when calling it from another class:

blogPost.Status = BlogPostStatus.Published;

vs

blogPost.Publish();

The side effects of the first option are not at all obvious and this lack of clarity should always be avoided.

Of course, what you see in most code bases is no validation in the domain object at all. Instead this type of logic is found in the next layer up. This can result in:

Longer methods mixing domain specific logic with orchestration, persistence and other concerns.

Duplication of validation logic between different actions.

Difficulty testing the pure domain logic due to external dependencies (the needs to use mocks)

As we might expect by now, EF will not function correctly if we completely remove the setter from every property but changing the access level to private solves the issue well enough:

public class BlogPost { public int Id { get; private set; } ... }

This way, all properties are read-only outside the class. To allow updates to our domain classes, we introduce action-style methods such as the Publish method shown above.

By removing the parameterless constructor and public property setters and adding action-type methods, we now have domain objects which are always valid and contain all the business logic directly related to the entities in question. This is a great improvement. We have made our code more robust and simpler at the same time. All code that we have added to the domain objects can be removed from higher up the call stack where it is often duplicated in several different places.

While we could discuss other DDD concepts such as domain events and the use of the domain services via the double dispatch pattern, their advantages, particularly with respect to simplicity are far less clear cut. One DDD concept which does generally simplify your code, is the use of value objects which we will discuss next.

Introduce value objects

Value objects are immutable (no changes allowed after instantiation) objects which do not have an identity of their own. Value objects can often be used to take the place of one or more properties in a domain object.

Classic examples of value objects include money, addresses and coordinates but it can also be beneficial to replace a single property with a value type instead of using a string or int. For example, instead of storing a phone number as a string, you could create a PhoneNumber value type with built-in validation as well as methods to extract dialing code etc.

The code below shows a money value object implemented as a class for use with EF:

public class Money { [StringLength(3)] public string Currency { get; private set; } public int Amount { get; private set; } private Money() { // just for EF } public Money(string currency, int amount) { // todo validation Currency = currency; Amount = amount; } }

Currency and Amount are intrinsically linked. Both pieces of information are required for the data to be useful. Therefore it makes sense to model them as such. Note the use of a parameterised constructor and private property setters in exactly the same way as we used when modeling domain objects. A private parameterless constructor is also required here for Entity Framework.

In the context of (RDBMS) data persistence, a value type does not live in a separate db table. To allow us to use value objects in Entity Framework, a small addition is required. This differs depending on the EF version that you are using.

In EF6, we simply decorate the value object with the [ComplexType] attribute:

[ComplexType] public class Money { ... }

In EF Core, starting from version 2.0, we can use the less obvious OwnsOne method of the fluent API:

public class BlogContext : DbContext { ... public DbSet<BlogPost> BlogPosts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<BlogPost>().OwnsOne(x => x.AdvertisingFee); } }

UPDATE: Entity Framework Core 2.1 reintroduces the attribute approach for identifying value objects. Rather than [ComplexType], we must use the new [Owned] attribute. See MSDN for full details.

This assumes that we are using the Money value object on our blog post entity as follows:

public class BlogPost { ... public Money AdvertisingFee { get; private set; } ... }

After creating and running a migration, we will find that our database table now contains two additional columns:

AdvertisingFee_Currency AdvertisingFee_Amount

The benefits of using value objects are much the same as the move to rich domain models. A rich domain model removes the need for the calling code to validate the domain model and provides a well-defined abstraction to program against. A value object validates itself so the domain model housing the value object property does not itself need to know how to validate the value type and can be simplified. All very clear and simple.

A word of caution

When you move from an anemic domain model to a richer model, your will immediately appreciate the benefits of encapsulating domain level business logic in your domain objects. Note that it is common to try and take things too far however. Creating a method on your domain object to perform validation and then update multiple properties is undoubtedly a good thing. Sending an email from your domain object or saving to a database is not something that you probably want to do. It is important to be aware that having a rich domain model does not negate the requirement of another layer to orchestrate these higher level concerns. This is the job of the application service or the command handler depending on your architecture.

A note about unit testing

One perceived negative of a rich, self-validating domain model is that it can make testing harder. With public setters, you can simply assign individual values to any domain object property. This allows you to assign the exact value you require directly to get an object into a certain state for a test. If you lock down your properties and constructor then this approach is not possible. This is not a bad thing. Yes it can make things slightly harder to set up but what you are doing is ensuring that your test is valid.

It also makes testing the logic within the domain objects themselves very simple. While the unit tests for your application service / command handlers will almost certainly require some level of mocking, you should find that most of your domain object tests are much simpler to construct and are often free from dependencies that require mocking.

Conclusion

This article showed three very simple techniques that you can use to move from an anemic domain model to a rich domain model when using Entity Framework and EF Core. The use of a parameterised constructor allows us to ensure that our domain model is valid when instantiated. The removal of public property setters ensures that our models remain in a valid state for their entire lifetimes. The introduction of methods to act on the domain model and internally perform validation and change state allows us to centralise business logic and simplify the calling code. Finally we looked at the use of value objects and explained how they can take this simplification and logic encapsulation one step further.

Useful or Interesting?

If you liked the article, I would really appreciate it if you could share it with your Twitter followers.

Comments