Separating the Read Model

A typical architecture of a .NET web application is to use EF Code First for data access and MVC to render the web pages. The data model in the database is usually (and should be!) normalized. A normalized data model is also great for updates, but when displaying data it is not enough. E.g. in a table of cars I don’t want to display a numeric, database internal id of the car’s brand. I want to display the name of the brand. Creating a separate read model simplifies that.

Separating the read and write models are a key concept of the recently popular CQRS (Command Query Responsibility Separation) architecture. I won’t go as far as the CQRS model does, but rather show a simple way to dress the write model’s car entity with the values required for displaying.

My key objective is to get a model where I can get everything needed for rendering a view to the user in one fetch from the database, with a minimum of extra coding and mapping code.

The Read Model

For this example I have a cars table with a foreign key (giving a navigation property) to a brands table. When displaying a list of cars I of course want to display the name of the brand, not its internal database id that’s stored in the cars table. A simple way to handle that is to wrap the car entity class in a read model (which can be used as our view model in MVC).

public class CarReadModel
{
    public Car Car { get; set; }
 
    public string BrandName { get; set; }
}

Querying for the Read Model

The purpose of the read model is to fetch everything needed to display the web page in one call to the database. That can be done with a LINQ query that projects the result into a CarReadModel object with select.

from c in ctx.Cars
where c.CarId == id
select new CarReadModel
{
    Car = c,
    BrandName = c.Brand.Name
}

The entire read model is fetched in one efficient call to the database. The read model contains everything needed for displaying.

In this case it’s perfectly fine to include the entire cars entity in the read model because the entity is so lightweight. If the entity contains any large fields (e.g. a scanned registration certificate) that is not to be displayed in all views it would be better to list the required fields explicitly in the read model instead.

Everything works fine with this code, but if the CarReadModel class is to be reused for different queries, the projection (the select part of the query) should be reusable. I’ll show a simple way to do that next week.

1 comment

  1. An ORM should allow you to map the same class more than once. Assuming, that your object model covers all relationships needed for reporting, you just leave out all unnecessary properties in the alternative mappings. Of course, these mappings can be used in multiple queries.
    Furthermore, reference data, that – like a car brand – rarely changes over time, can be cached, thus eliminating most database JOINs.
    With a dedicated data access layer, the optimizations aren’t scattered all over the application.
    In a nutshell, with a sufficiently sophisticated ORM you can use the same object model for reading and writing without sacrifing reading performance.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.