Entity Framework Code First and Enum Support

In my previous post, I showed how to use the new EF 5 Enum support and have your lookup table populated as enum values. This post was for the Database First workflow which we all used when we started using Linq to Sql or the first EF release. We used to see an O/R Mapper as one that reflects database structure in object oriented manner, so building your model from a database looked like the right way to go.

Starting from EF 4.1, you can start with your code and let EF make the database for you – the Code First workflow. With this workflow, you can forget about adding tables, columns and relations with the database tools.

Note: For using Code First with existing database look in this post.

For this demo, the classes structure is as follows:

1. An enum for the possible status of a student:

2. A Student class:

3. A DbContext class:

Running this code will create the database:

As expected, there is only one table named Students in the database. A lookup table for the enum was not created since it doesn’t have a corresponding DbSet, and we can’t add one since the generic type of a DbSet must be a reference type and enum isn’t. We would like to create a table for the enum, fill it with the enum values and add a FK in Students table to this table.

EF Code First mechanism has some conventions which determine how to create the database structure. For example, if your class has an integer property named “ID” (case-insensitive) or “YourClassNameID”, EF will create a primary key column for this property.

There are several ways to customize the way Code First acts:

  1. Using Data Annotations. You can customize column or table names, add keys, add constraints and so on. You can’t create a new table with no DbSet.
  2. Overriding DbContext.OnModelCreating. Inside this method you can use the Fluent API to customize the model creating process. You can do more advanced changes but still you are limited to an existing DbSet.
  3. Using Migrations. This method allows you to add code to apply more changes to the database after you’ve created it in the first place. Here you can also create more tables and add plain Sql code.

To start using Migrations, you have to enable it first. Open the Package Manager Console From Tools -> Library Package Manager -> Package Manager Console. In the tool window make sure your project is selected in the Default Project: drop down.

Run the following command: Enable-Migrations

After running the command, you’ll see a new folder in your project named Migrations. In this folder there are two files. One is Configuration.cs which applies to the migrations configuration. The other is InitialCreate.cs (prefixed with a number) that has the following code:

This code is creating your database according to your classes. The method Up is executed when the database is upgraded to this version. The method Down is executed when the database is downgraded from this version, and should rollback the changes made in the Up method.

I prefer to add another migration to change the database and not change the initial one. This way it will be easy to go back to the default behavior of Code First.

To add a migration, go back to the Package Manager Console window and run the following command: Add-Migration AddEnum. The AddEnum is the migration name and you can change it.

After running this command you’ll see another file in the Migrations folder named AddEnum and prefixed with a number. This file has a class with empty Up and Down methods.

In those methods we would like to add the lookup table as follows:

  • In the Up method:
    • Create the table.
    • Fill it with data.
    • Add a FK to the Students table.
  • In the Down method:
    • Remove the FK.
    • Delete the table.

The code for this migration:

To run the migration run the following command in the Package Manager Console window: Update-Database

After running this command, we have a lookup table with the enum values.

Now what should you do if you add another value to your enum later? You can add another migration and add only the values that are not in the table, however each migration run only once and you’ll have to add another migration with the same code but other values anytime you add a new value.

What we need here is a method that run every time we run the Update-Database command. For that we can use the Seed method in the Configuration.cs file mentioned before. (Notice that every time you update the database you see a message Running Seed method). There is no need to write a downgrade code for this since in the AddEnum code we delete the table completely.

We should add the following code in the Seed method:

Now any value we add to the enum will be added to the table when we run the Update-Database command even if there is no migration that wasn’t applied before.

This solution is much more cleaner than my solution to the Database First workflow. Using designers is fun and I love it but hook into them is much more complicated. Using Code First you got much more simple control over the model generation.

 

Posted in Code First, Entity Framework, Enum by Amiram Korach at October 17th, 2012.
Tags: , , , ,

Leave a Reply

%d bloggers like this: