Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Code First Migrations With Entity Framework

4.93/5 (43 votes)
18 Nov 2014CPOL7 min read 216.5K   2.8K  
This article will provide answers to the following questions relevant to relationships in Entity Framework: whether or not to create a database, how to add / remove a field from an existing table, how to avoid data loss and how to get a database script that has the changes.

Introduction

My previous article “Relationship in Entity Framework Using Code First Approach With Fluent API” introduced relationships of entities but when you read that article, some questions will occur to you such as:

  1. Should I create a database each time?
  2. How can I add / remove a field from an existing table?
  3. How can I avoid data loss when a field is added or removed from an existing table?
  4. Can I get a database script that has the changes in the database?

This article will provide the answers for all those questions.

As you saw in the previous article, you add some entity classes to a project and it might be that you add or remove fields from entities. That's why the data model changes frequently. We have some configuration options in Entity Framework to create a database, such as create a database if it does not exist, automatically drop and re-create the database each time when you change an entity or data model.

Suppose you have first the configuration option that creates a database if it does not exist and now you add a new entity and run the application. Then you get an error such as Database "xx" cannot be created because it already exists but when you use the second configuration option and you add or remove a field from the entity or change entity classes or make a change in a DbContext class, the next time the application is run it automatically deletes the existing database, creates a new one that matches the model and seeds it with test data.

The Entity Framework migration feature enables us to change the entity or data model and deploy these changes to the database server by updating the database schema without having to drop and re-create the database.

Our Roadmap Towards Learning MVC with Entity Framework

Create Database from Data Model

To understand the migrations in the Entity Framework Code First approach, we create an entity and define their configuration using the Fluent API. We will create two class library projects, one library project (EF.Core) has entities and another project (EF.Data) has these entities configuration with DbContext.

Let's define a very simple data model. We are just defining it in the EF.Core project. Below the Student class definition is the Student.cs file under the EF.Core project.

C#
using System;  
namespace EF.Core  
{  
   public class Student  
   {  
      public Int64 Id { get; set; }  
      public string Name { get; set; }  
      public int Age { get; set; }  
   }  
}

First of all, we install the Entity Framework package to the EF.Data project so we can use it.

From the Tools menu, click Library Package Manager and then Package Manager Console then choose default project EF.Data in it, which means always choose that project where you want to install a package.

At the PM> prompt, enter the following command:

PM> Install-Package EntityFramework -Version 5.0.0

Install Entity Framework

Figure 1.1: Install Entity Framework

We add a reference of the EF.Core project DLL to the EF.Data project so that we could use the data model to create the database table. Thereafter, we define the configuration for the preceding data model that will be used when the database table is created. The configuration defines another class library project EF.Data under the Mapping folder. For the Student data model, we create the StudentMap configuration class definition in the StudentMap.cs file under the EF.Data project.

C#
using System.ComponentModel.DataAnnotations.Schema;  
using System.Data.Entity.ModelConfiguration;  
using EF.Core;  
  
namespace EF.Data.Mapping  
{  
  public class StudentMap : EntityTypeConfiguration<Student>  
    {  
      public StudentMap()  
      {  
          //key  
          HasKey(t => t.Id);  
  
          //property  
          Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);  
          Property(t => t.Name);  
          Property(t => t.Age);          
  
          //table  
          ToTable("Students");  
      }  
    }  
} 

Now define the connection string in the App.config file under the EF.Data Project so that we can create a database with an appropriate name. The connectionstring is:

XML
  <connectionStrings>  
    <add name="DbConnectionString" connectionString="Data Source=sandeepss-PC;
    Initial Catalog=EFCodeFirst;User ID=sa; Password=****" providerName="System.Data.SqlClient" />  
</connectionStrings> 

Now we create a context class EFDbContext (in EFDbContext.cs) that inherits the DbContext class. In this class, we override the OnModelCreating() method. This method is called when the model for a context class (EFDbContext) has been initialized, but before the model has been locked down and used to initialize the context such that the model can be further configured before it is locked down. The following is the code snippet for the context class.

C#
using System.Data.Entity;  
using EF.Data.Mapping;  
  
namespace EF.Data  
{  
    public class EFDbContext : DbContext  
    {  
        public EFDbContext()  
            : base("name=DbConnectionString")  
        {  
  
        }  
  
        protected override void OnModelCreating(DbModelBuilder modelBuilder)  
        {  
            modelBuilder.Configurations.Add(new StudentMap());  
        }  
    }  
} 

As you know, the EF Code First approach follows convention over configuration so in the constructor we just pass the connection string name the same as an App.Config file and it connects to that server. In the OnModelCreating() method, we add a configuration class object to DbModelBuilder.

We create a console application EF.Console to create a database and insert data into the database table. Implement the Main method in Program.cs as shown below. This code creates a new instance of our context and then uses it to insert a new Student.

C#
using System;  
using EF.Core;  
using EF.Data;  
  
namespace EF.Console  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            System.Console.Write("Enter your name : ");  
            string name = System.Console.ReadLine();              
            System.Console.Write("Enter your age : ");  
            int age = 0;  
            Int32.TryParse(System.Console.ReadLine(), out age);  
  
            using (EFDbContext context = new EFDbContext())  
            {  
                Student student = new Student { Name = name, Age = age };  
                context.Entry(student).State = System.Data.EntityState.Added;  
                context.SaveChanges();  
            }  
            System.Console.ReadLine();             
        }  
    }  
}  

Now, we run the preceding code and get the result that the database was created in SQL Server and inserted a row into the Student table.

Database Created

Figure 1.2: Database Created

Now we update the data model by addiing a new field IsCurrent in it so the update of the Student class will be such as:

C#
using System;  
  
namespace EF.Core  
{  
   public class Student  
    {  
       public Int64 Id { get; set; }  
       public string Name { get; set; }  
       public int Age { get; set; }  
       public bool IsCurrent { get; set; }  
    }  
} 

As per the preceding explanation, we also need to update its configuration class StudentMap such as:

C#
using System.ComponentModel.DataAnnotations.Schema;  
using System.Data.Entity.ModelConfiguration;  
using EF.Core;  
  
namespace EF.Data.Mapping  
{  
    public class StudentMap : EntityTypeConfiguration<Student>  
    {  
        public StudentMap()  
        {  
            //key  
            HasKey(t => t.Id);  
  
            //property  
            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);  
            Property(t => t.Name);  
            Property(t => t.Age);  
            Property(t => t.IsCurrent);  
  
            //table  
            ToTable("Students");  
        }  
    }  
}  

Thereafter, we update the Main method of Program.cs so that we can insert a value for the student as the current student or not.

C#
using System;  
using EF.Core;  
using EF.Data;  
  
namespace EF.Console  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            System.Console.Write("Enter your name : ");  
            string name = System.Console.ReadLine();  
            System.Console.Write("Enter your age : ");  
            int age = 0;  
            Int32.TryParse(System.Console.ReadLine(), out age);  
            System.Console.Write("You are current student");  
            bool isCurrent = System.Console.ReadLine() == "Yes" ? true : false;  
  
            using (EFDbContext context = new EFDbContext())  
            {  
                Student student = new Student { Name = name, Age = age, IsCurrent = isCurrent };  
                context.Entry(student).State = System.Data.EntityState.Added;  
                context.SaveChanges();  
            }  
            System.Console.ReadLine();  
        }  
    }  
} 

Now, we run the application and get this error:

Error to add a record to database

Figure 1.3: Error to add a record to database

The preceding error shows that the data model has been changed since the database was created and it's right. We have a solution to resolve this error that don't reinitialize context so we define a static constructor in context class and set database initializer null in it. Let's see the following updated code snippet of context class:

C#
using System.Data.Entity;
using EF.Data.Mapping;

namespace EF.Data
{
    public class EFDbContext : DbContext
    {
        static EFDbContext()
        {
           Database.SetInitializer<EFDbContext>(null);
        }

        public EFDbContext()
            : base("name=DbConnectionString")
        {

        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new StudentMap());
        }
    }
} 

Now we run the application and get this error.

 Database Update Exception

Figure 1.4 Database Update Exception

The preceding error occurs because our data model entity is updated in code while related database table is not updated. We have two solutions to resolve this error, either delete the database or use migrations. The first one is not useful since in that case we lose all the data from the database so we will see the second solution in the next section.

Code First Migrations

The Code First Migration is used to update the database. Here we will look at how to use it in our application. Let's see it step-by-step.

From the Tools menu, click Library Package Manager and then Package Manager Console then choose the default project EF.Data in it. That means always choose the project with your context class for migrations.

At the PM> prompt, enter the following command:

PM> enable-migrations

When running the preceding command, you will get a console window such as:

Enable code first migration

Figure 1.5: Enable code first migration

This command adds a new folder, Migrations, in the project EF.Data and this folder contains a configuration file with default settings.

Now we add to the configuration settings in the Configuration class constructor, one to allow migration and another for no data loss when migrating. The excerpt of the Configuration class for these properties is:

C#
AutomaticMigrationsEnabled = true;  
AutomaticMigrationDataLossAllowed = false; 

We set the AutomaticMigrationEnabled property to true; that means we are using automatic code first migration and another property AutomaticMigrationDataLossAllowed is set to false. That means that during the migration, no existing data is lost from that migration of the table of the database. The entire Configuration class is as follows:

C#
namespace EF.Data.Migrations  
{  
    using System;  
    using System.Data.Entity;  
    using System.Data.Entity.Migrations;  
    using System.Linq;  
  
    internal sealed class Configuration : DbMigrationsConfiguration<EF.Data.EFDbContext>  
    {  
        public Configuration()  
        {  
            AutomaticMigrationsEnabled = true;  
            AutomaticMigrationDataLossAllowed = false;  
        }  
  
        protected override void Seed(EF.Data.EFDbContext context)  
        {  
            //  This method will be called after migrating to the latest version.  
  
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method   
            //  to avoid creating duplicate seed data. E.g.  
            //  
            //    context.People.AddOrUpdate(  
            //      p => p.FullName,  
            //      new Person { FullName = "Andrew Peters" },  
            //      new Person { FullName = "Brice Lambson" },  
            //      new Person { FullName = "Rowan Miller" }  
            //    );  
            //  
        }  
    }  
}  

The seed method is used to insert default values into the database table.

Thereafter, we will update the database using the Package Manager Console. To update the database at the PM> prompt, enter the following command:

PM> Update-Database -Verbose

The "-Verbose" flag specifies to show the SQL Statements being applied to the target database in the console. You get results as in the following figure in the Package Manager Console.

 Update existing database

Figure 1.6 Update existing database

Now we check the database and add a new record using our console application. We find that in the database there is no data loss and the application is running smoothly without throwing any exception. You can write the following query in the database and get the results as in Figure 1.7.

SQL
SELECT [Id],[Name],[Age],[IsCurrent]FROM [EFCodeFirst].[dbo].[Students]  

Retrieve data from student table

Figure 1.7: Retrieve data from student table.

Conclusion

This article introduced Code First Migrations using Entity Framework. I hope that these two articles will provide a clearer understanding of how to use the Entity Framework in our application. If you have any concerns, post as a comment or directly connect by https://twitter.com/ss_shekhawat.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)