Enums and Lookup Tables with EF Code First

With EntityFramework’s support for enums, there is no longer any need to include lookup tables in the model. But I do want to have them in the database for integrity, even with code first.

I’ve been thinking for some time about to handle enums with code first. The idea behind code first is to be able to write the code as close as possible to how object oriented code is normally written. For enums that means that the enum definition itself is the constraint that is used to ensure that only valid values are used in the code.

For databases it would be possible to use a column constraint, but the normal way is to use a lookup table where the valid values are present. Any column in the database mapped against the enum type is then a foreign key to the lookup table to ensure integrity of the data.

What I would prefer is a solution where the lookup table is present in the database, but not mapped against any entity in the code.

Code or Configuration or Configuration in Code?

With DevOps bringing source control to configuration files and publishing to production servers being automated – bringing both code and configuration over on the same time, the difference between code and config has become less than ever (if it even exists).

A few weeks ago I reread Mike Hadlow’s brilliant post The Configuration Complexity Clock. As I’m also in the middle of setting up publishing routines for a web application I started to think about the difference between configuration and code. The more I think about it, the less clear the difference is.

A simple attempt to differentiate them would be to look at where they are stored.

  • Everything in source files that are consumed by the compiler is code.
  • Everything in configuration files that are read at runtime is configuration.

Unfortunately that is not the entire truth. For example the route config in an ASP.NET MVC application is a kind of configuration – but it is done in code. The same is true for the Entity Framework Code First mappings – it is done in code (either through attributes or a fluent API), but is a kind of mapping configuration. An example of the other way around is startup configuration scripts (think of *nix .bashrc or the old autoexec.bat on DOS systems). It is configuration, but is run as a script.

There are definitely cases where it is not that simple to define what is configuration and what is code.

And does it really matter?

Merging Expression Trees to Reuse in Linq Queries

Reusing parts of LINQ queries is easily done by chaining methods returning IQueryable. Unfortunately that doesn’t cover some senarios like reusing member initialization lists. To handle such a situation I wrote a Merge extension method for select expressions.

For this post we’ll load the data required for a list of cars and a detail view for one car. When loading the details, more fields are required than when just loading the list. With the merging helper method we can reuse the query for the basic list and just extend it with the added properties.

The basic info for the list view is held in a CarBasicInfo DTO class. The data for the detail view is held in a CarExtendedInfo class which is derived from the CarBasicInfo class. A helper method contains the Select() call to map Car entities to the basic DTO. Now the Merge extension method can be used to merge an expression with the initialization of the additional fields for the extended DTO with the existing helper method for the basic fields.

private Expression<Func<Car, CarBasicInfo>> basicSelect =
    c => new CarBasicInfo
    {
        CarId = c.CarId,
        RegistrationNumber = c.RegistrationNumber
    };
 
var car = ctx.Cars.Select(basicSelect.Merge(c => new CarExtendedInfo
{
    Color = c.Color,
    BrandName = c.Brand.Name
})).Single(c => c.RegistrationNumber == "ABC123");

The RegistrationNumber field is not mentioned in the init list – it is populated by the basic select in the SelectBasicInfo helper method. To accomplish this some (non trivial) rewriting of expression trees is in the Merge method.

EF Code First DbContext.SavingChanges

Unfortunately there is no SavingChanges event on the code first DbContext, but there is a way to get to it.

The DbContext used for data access with Entity Framework Code First has a simplified API compared to the ObjectContext which is good. Unfortunately it is a bit too simple sometimes. For example there is no built in event that can be used to act before pending changes are written to the database. Fortunately, there is a way to get to the underlying ObjectContext which has such an event.

[TestMethod]
public void TestSavingChanges()
{
    using (var ctx = new CarsContext())
    {
        var objCtx = ((IObjectContextAdapter)ctx).ObjectContext;

        bool eventCalled = false;

        objCtx.SavingChanges += (sender, args) => eventCalled = true;

        ctx.SaveChanges();

        Assert.IsTrue(eventCalled);
    }
}

Of course it would be really simple to create an own event inside an override of SaveChanges but having a built in one is even more simple. There is also a ObjectMaterialized event that is fired each time an object is loaded from the database as well as some additional methods and properties that are not available directly on the DbContext.

Make the DbContext Ambient with UnitOfWorkScope

The Entity Framework DbContext (or LINQ-to-SQL DataContext) is a Unit Of Work implementation. That means that the same DbContext should be used for all operations (both reading and writing) within a single web or service request. That means that there are a lot of different places where the DbContext have to be accessed. To avoid having to pass the DbContext around as a parameter, I’ve created a UnitOfWorkScope that makes the DbContext ambient and easily accessible.

A common beginners problem when working with Entity Framework or LINQ-to-SQL is to have too short life times of the DbContext. A problem that I’ve seen many questions about on Stack Overflow is when questions are encapsulated in repositories or helper methods. Inside each method a new DbContext is created for that specific read. Later, when the returned entity has been updated and is to be saved the problem occurs. The entity should be saved using the same DbContext that once read it from the database to allow change tracking to work properly. Clearly, having separate DbContexts is a problem.

The first attempt to solve it is usually to pass the DbContext around. That only solves half the problem though, that of accessing it. The other half of the problem is to decide where to call SaveChanges to persist the changes done. Calling it from every method making changes spoils the entire unit of work concept. Trusting the creator of the context to know when any of a myriad of called functions have made changes seems risky.

I’ve been looking for a better way to handle the DbContext and have come up with an ambient DbContext, using a UnitOfWorkScope which is similar to TransactionScope.

The main features of the UnitOfWorkScope are:

  • The first method in the call chain opening a UnitOfWorkScope creates an ambient DbContext.
  • Subsequent methods in the call chain utilizes the same DbContext.
  • Changes are only saved if all participating scopes called SaveChanges
  • Read only mode is available, where data is read using the existing DbContext, but no changes need to be saved. This is useful for GetSomeThing methods that are used both for pure reading and for reading for update.
Software Development is a Job – Coding is a Passion

I'm Anders Abel, a systems architect and developer working for Kentor in Stockholm, Sweden.

profile for Anders Abel at Stack Overflow, Q&A for professional and enthusiast programmers

The complete code for all posts is available on GitHub.

Popular Posts

Archives

Series

Powered by WordPress with the Passion for Coding theme.