Thursday, March 8, 2012

Code First MIgrations

I really like work with the entity framework. It is one of the tools that every developer should use. Entity Framework help us to create a database from scratch using one of the newest version called code first.
I like code first, but one of the biggest problem was that every time that the database was recreated by using any initializer, like dropdatabasealways or dropdatabaseifmodelchanges we ended up loosing data. In the Entity Framework 4.3.1 we find an answer for that problem called migrations. Creating a new database with migrations is easy. However, using an existing database is a little bit challenging. So, instead of showing how work with migrations creating a new database, I am going to show how
to work with migrations with an existing database.

In this example I worked with VS 2010, I used C#, Nuget, Entity Framework powertools and AdventureWorksLT Database.
First thing to do: Create a New Solution in Visual Studio. I followed the same organization that I saw in one of the videos of Julie Lerman (BTW, I just got her book DBContext, yeahhhh).
The order is as follow:
One Console Application App for our main project
Two Class Library, one for our Context (Datalayer), and another one for our domain classes. Which after I created I deleted the default class and I have the following structure:

Now, using Nuget, add entity framework to the solution. The projects that I added were the console app and the datalayer.


Remember that I had installed EF power tools, which you are going to use to get all the tables and the dbcontext for our database doing reverse engineering. Right click on the data layer and click on reverse engineering. After that chose AdventureWorksLT database.


So far, so good. Now we have two folders in our datalayer project, one for entities and another for mapping. EF powertools helped us to do this without write all that code by ourselves.
Then I cut the Entities folder and I paste it into the DomainClasses project. After that change every reference to the Entities in your project.

using DataLayer.Entities;
to
using DomainClasses.Entities;



Of course moving those folders will create references error to our project. One thing you have to do is add the DomainClasses project as reference to the Datalayer, and also change the using clause for both entities and mapping references.

Build your project and you are almost there.

Let's put some code in the Console app.
        static void Main(string[] args)
        {
            var Context = new AdventureWorksLTContext();
            foreach (Address ad in Context.Addresses )
            {
                Console.WriteLine(ad.AddressLine1);
            }
            Console.ReadLine();
        }
Before run this, check your Maps classes (AddressMap, ProductMap, etc.) there is a problem with these classes. Look at this line in the AddressMap class:

this.ToTable("Address");

That line is saying that our table is using dbo schema, which is not. If we open Sql Express we will notice that the schema for almost all the tables is SalesLT, so you should use:

 this.ToTable("Address","SalesLT");

Change that for all the tables that have different schema than dbo.

At this moment our project does not know anything about migrations, so using Nuget let's enable migrations.

Using the Nuget Package Manager Console pointing to DataLayer as Default project run the following command: Enable-Migrations.


After that we need our first migration, which must be empty because we have a database already! so, first we need to run this command on the Nuget Package Manager Console:

Add-Migration Initial

Which gave us a class called initial with two methods, Up and Down. Up create all the tables and Down drop all the tables. But, since we have a database and we do not want to drop it let's delete these two methods so we left them empty.

Also, you have to add the following lines in your app.config in your console app (After defaultConnectionFactory tag):
<entityFramework>
   .....
   .....
   <contexts>
      <context type="DataLayer.AdventureWorksLTContext, DataLayer">
        <databaseInitializer
          type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[DataLayer.AdventureWorksLTContext, DataLayer],
               [DataLayer.Migrations.Configuration,  DataLayer]], EntityFramework" />
      </context>
    </contexts>
<entityFramework>

After that run the following command: update-database, we are going to see the migration table in the system tables in AdventureWorksLT.

Run the console app and you will get the list of addresses. There it is, use code first with an existing database.

Happy Code First Coding!




No comments:

Post a Comment