I attended a local meetup yesterday and posed a question about a static factory method I was using to create validators that would handle all validation of my entities before persisting them in my database (I’m using Entity Framework 6 as my Object-relational mapper). The solution has worked well for years, but it was getting to be a lot of code, and a lot of duplication which has been a code smell for a while.
I kind of had a hunch that people would bring up data annotations / fluent API to remove the need for much of the validation I am doing and offload that work to the ORM, but I wasn’t sure if they would handle all of the validations I needed (some validations require a little more complicated logic than just validating whether data field lengths are valid). After discussing some of these cases and options for handling those (I’ll have to make another post about that when I get to actually converting my validators), I decided it was time to update all of my EDMX database first mappings to Code first. Afterall, EDMX is dead, so why not get onboard now if it was feasible to do so?
While the process is relatively straightforward, I found a couple of different options and ran into some snags, so I thought I would share a little about my experience making the change. This post is also going to discuss the process of enabling data migrations, which isn’t technically necessary, but a great idea for making sure your database schema stays current with the changes you’re making using code first.
The first thing you have to do is have your models created. The EDMX file previously created them under whatever namespace you set in the EDMX file properties, but now you have to get those models (and the DbContext) added as standalone classes before you can feel safe about blowing away your old EDMX file for good. There are two methods I discovered to do this. I came across a really nice guide to doing this migration here that discusses the first method below: http://devgush.com/2014/02/24/migrating-a-project-from-database-first-to-code-first/ (Note that steps 3-7 are going to be required regardless of which method you choose. Steps 1-2 are for migrating your EDMX-based database-first objects and mappings to code first and steps 3-7 are for enabling migrations and getting your database setup for the first time).
Method 1: Use Entity Framework Power Tools
This is the method outlined in steps 1-2 of the article above, and it worked very well. It involves downloading a Visual Studio Extension and reverse engineering the model files. I did run into a couple of snags, but they were easily overcome:
- I’m using Visual Studio 2015 as my IDE and Entity Framework Power Tools only supports up to VS 2013.Here is a link to a post that discusses this in more detail than I will go into here: http://thedatafarm.com/data-access/installing-ef-power-tools-into-vs2015/. In a nutshell, here is what you have to do to get around this working in VS2015:
- Download the installer package: https://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d
- Change the extension to “.zip”
- Extract to folder
- Modify the file “extension.vsixmanifest” (open with a text editor) by adding VisualStudio version 14.0 as a child element to the list of Supported Products
- Re-compress as zip (Note: it’s important to select all the files/folders in the root folder and compress, not by compressing the outer folder itself. The files for the extension must be in the root, and compressing the outer folder adds a folder to the top layer of the compressed file).
- Change the file extension back to “.vsix” (provide link to EFPowerTools).
- Apparently Update 2 of VS 2015 had some adverse effects on the step when you try to Reverse Engineer Code First with VS Power Tools (http://stackoverflow.com/questions/36421344/visual-studio-2015-update-2-breaks-ef-reverse-code-engineer-vsix). I received this error:
One or more errors occurred while processing template ‘Entity.tt’. error : An exception was thrown while trying to compile the transformation code. The following Exception was thrown:
I am not 100% sure why, but simply changing the target framework (I selected the one previous), attempting to build, and then changing it back to what you want resolved the issue for me.
Method 2: Use Add New > EF Code First from Database
This method is pretty straightforward, and I didn’t run into any snags really. Here is what I did:
- I added a folder called Models under the root of my project because I like having all the models and context in their own namespace. I often organize the project containing my entities to also include interfaces to services and repositories, so having a namespace separation is desirable.
- Right click on the project and use Add New > EF Code First from Database (under the Data filter on the left side) and run the utility.
While method 2 works right out of the box and is generally easier to run, I ended up preferring method 1. The biggest difference I could see between the two methods is that all of the models generated with method 2 use Data Annotations instead of the Fluent API to set restrictions on properties. I personally prefer the fluent API to annotations because fluent API feels like it keeps the models themselves very clean. It seems to do a better job of obeying the separation of concerns principle. Another difference that I think works in method 2’s favor is that it allows you to choose which tables you want to import. Method 1 seems to just import every table in the database, regardless of what you had in your EDMX file. This led to me having to delete some unused models after import.
Database Migration Notes (applies to either method above)
- Before you can enable migrations in step 3 from the article linked above (http://devgush.com/2014/02/24/migrating-a-project-from-database-first-to-code-first/), your project has to build. Some things to look out for:
- Since the models generated were put into a different namespace than my EDMX file used, I had to basically find and replace all the using statements in my solution that relied on the old namespace.
- I had some partial classes that extended my entities (mostly to add interfaces to them) – I decided to just update all of the entities generated by putting any interfaces or additional properties directly on the entity itself rather than in a separate partial class.
- If you had any custom names for reference properties on entities in your EDMX model, you will have to update reference property names in your model files (for both methods above) and the foreign key generation of the mapping files (for method 1 above only). For example, assume you have an object “Company” with two properties: “DefaultBillingAddressID” and “DefaultShippingAddressID.” Both of these properties have Foreign Key constraints to the “ID” column of the Address table. Entity Framework generally names the corresponding reference properties something like “FKProperty1”, “FKProperty2”, and so on – in this particular case it would probably name them “Address1” and “Address2.” I always rename those to something useful so I can remember exactly which one they are – “DefaultBillingAddress” and “DefaultShippingAddress” in this case.
- I was able to skip step 5 completely because I had already updated my context to the new DbContext previously.
- During step 6 (adding the migration), I had to remove the “name=” part of the default constructor that was being passed into the base constructor (DbContext) of the Context class. It seems that migrations require a default constructor (I wasn’t able to find a way around that).
- When Updating your database, the user in your connection string must have create table permissions in order to create the _MigrationHistory table.
- If you’re not using the default connection string added to your startup project’s web.config/app.config file, you can use the -ConnectionStringName flag with Update-Database and give it the name of the connection string you want.
- If you have objects that the EDMX file created for stored procedures, you’ll want to copy the object classes into your own class files before deleting the EDMX file. I moved the namespace to *.Models.StoredProcedures so that it was easier to keep separate which objects were stored procs and which were standard entities.
- If you extended any of your classes by adding a partial class, you’ll want to Ignore any properties that don’t exist on the datastore or you’ll run into problems. Even if your extension methods / properties are in a separate class, EF will try to execute them against the datastore.
- Be careful with your money – I found this out about a week later: If you’re using Entity Framework Code First, be careful with your money!
In the end, it only took a few hours for me to upgrade about 10 projects using these methods. I had a lot of objects and references to update due to namespacing issues and custom naming on reference properties, so if you don’t have as many of those issues to deal with, it should go even smoother for you.