Click here to Skip to main content
15,867,568 members
Articles / Database Development / SQL Server

Learning Entity Framework (Day 2): Code First Approach and Migrations in Microsoft .NET Entity Framework

Rate me:
Please Sign up or sign in to vote.
4.98/5 (14 votes)
28 Sep 2018CPOL14 min read 27.6K   762   20   22
Code First Approach and Migrations in Microsoft .NET Entity Framework

Table of Contents

Introduction

The intent of this article is to explain the code first approach and code first migrations that Microsoft’s Entity Framework provides. In my last article, I explained the theory behind entity framework and the other two approaches, i.e., database first and model first approach. We’ll go step by step to explore the code first approach via which we can access database and data using entity framework in our application. I’ll use Entity Framework version 6.2 and .NET Framework 4.6. and Visual Studio 2017 for the tutorial. For the database, we would be using SQL Server. You can make use of local dB if you do not have SQL server installed.

Series Info

We'll follow a five-article series to learn the topic of entity framework in detail. All the articles will be tutorial form except the last where I'll cover the theory, history, use of entity framework. Following are the topics of the series.

Image 1

Code First Approach

The code first approach is the recommended approach with EF especially when you are starting the development of an application from scratch. You can define the POCO classes in advance and their relationships and envision how your database structure and data model may look like by just defining the structure in the code. Entity framework, at last, will take all the responsibility to generate a database for you for your POCO classes and data model and will take care of transactions, history, and migrations.

With all the three approaches, you have full control over updating the database and code as per need at any point in time.

Image 2

Using code first approach, a developer’s focus is only on code and not on database or data model. The developer can define classes and their mapping in the code itself and since now entity framework supports inheritance, it is easier to define relationships. Entity framework takes care of creating or re-creating database for you and not only this while creating a database, you can provide seed data, i.e., master data that you want your tables should have when the database is created. Using code first, you may not have a .edmx file with relationships and schema as it does not depend upon entity framework designer and its tools and would have more control over the database since you are the one who created classes and relationships and managing it. There is a new concept of code first migrations that came up which makes code first approach easier to use and follow, but in this article, I’ll not use migrations but old method of creating DB context and DB set classes so that you understand what is under the hood. Code first approach could also be used to generate code from an existing database, so basically it offers two methods in which it could be used.

Code First Approach in Action

  1. Create a new console application named EF_CF. This will give you Program.cs and a Main() method inside that.

    Image 3

  2. We’ll create our model classes now, i.e., POCO (Plain Old CLR Object) classes. Let’s say we have to create an application where there would be database operations for an employee and an employee would be allocated to some department. So, a department can have multiple employees and an employee will have only one department. So, we’ll create the first two entities, Employee, and Department. Add a new class to the project named Employee and add two simple properties to it, i.e., EmployeeId and EmployeeName.

    Image 4

    Image 5

  3. Similarly, add a new class named Department and add properties DepartmentId, DepartmentName, and DepartmentDescription as shown below:

    Image 6

  4. Since an employee belongs to one department, each employee would have a related department to it, so add a new property named DepartmentId to the Employee class.

    Image 7

  5. Now, time to add EntityFramework to our project. Open package manager console, select default project as your current console application and install entity framework. We already did this a couple of times before, so it won’t be a problem now on how to install it.

    Image 8

  6. Since we are doing everything from scratch, we need our DbContext class as well. In model first and database first, we got the DB context class generated. But, in this case, we would need to create it manually. Add a new class named CodeFirstContext to the project which inherits from DbContext class of namespace System.Data.Entity as shown in the following image. Now add two DbSet properties named Employees and Departments as shown in the following image:

    Image 9

    The final code may look like:

    C#
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF_CF
    {
        public class CodeFirstContext: DbContext
        {
            public DbSet<Employee> Employees { get; set; }
            public DbSet<Department> Departments { get; set; }
        }
    }

    Image 10

    Both DbContext and DbSet are our superheroes, in creating and dealing with database operations, and make us far abstracted, providing ease of use to us.

    When we are working with DbContext, we are in real working with entity sets. DbSet represents a typed entity set that is used to perform create, read, update, and delete operations. We are not creating DbSet objects and using them independently. DbSet can be only used with DbContext.

  7. Let’s try to make our implementation a more abstract and instead of accessing dbContext directly from the controller, let’s abstract it in a class named DataAccessHelper. This class will act as a helper class for all our database operations. So, add a new class named DataAccessHelper to the project.

    Image 11

  8. Create a read-only instance of the DB context class and add few methods like FetchEmployees() to get employees details, FetchDepartments() to fetch department details. One method each to add employee and add a department. You can add more methods at your will like the update and delete operations. For now, we’ll stick to these four methods.

    Image 12

    The code may look like shown below:

    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF_CF
    {
        public class DataAccessHelper
        {
            readonly CodeFirstContext _dbContext = new CodeFirstContext();
    
            public List<Employee> FetchEmployees()
            {
                return _dbContext.Employees.ToList();
            }
    
            public List<Department> FetchDepartments()
            {
                return _dbContext.Departments.ToList();
            }
    
            public int AddEmployee(Employee employee)
            {
                _dbContext.Employees.Add(employee);
                _dbContext.SaveChanges();
                return employee.EmployeeId;
            }
    
            public int AddDepartment(Department department)
            {
                _dbContext.Departments.Add(department);
                _dbContext.SaveChanges();
                return department.DepartmentId;
            }
        }
    }
  9. Let’s add the concept of navigation property now. Navigation properties are those properties of the class through which one can access related entities via the entity framework while fetching data. So while fetching Employee data, we may need to fetch the details of its related Departments and while fetching Department data, we may need to fetch the details of associated employees with that. Navigation properties are added as virtual properties in the entity. So, in Employee class, add a property for Departments returning a single Department entity and make it virtual. Similarly, in Department class, add a property named Employees returning the collection of Employee entity and make that virtual too.

    Image 13

    Following is the code for the Employee and the Department model.

    Employee

    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF_CF
    {
        public class Employee
        {
            public int EmployeeId { get; set; }
            public string EmployeeName { get; set; }
            public int DepartmentId { get; set; }
    
            public virtual Department Departments { get; set; }
        }
    }

    Department

    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Policy;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF_CF
    {
        public class Department
        {
            public int DepartmentId { get; set; }
            public string DepartmentName { get; set; }
            public string DepartmentDescription { get; set; }
    
            public virtual ICollection<Employee> Employees { get; set; }
        }
    }
  10. Let’s write some code to perform database operations with our code. So, in the Main() method of Program.cs class, add the following sample test code:
    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF_CF
    {
        class Program
        {
            static void Main(string[] args)
            {
                Department department = new Department
                {
                    DepartmentName = "Technology",
                    Employees = new List<Employee>
                    {
                        new Employee() {EmployeeName = "Jack"},
                        new Employee() {EmployeeName = "Kim"},
                        new Employee() {EmployeeName = "Shen"}
                    }
                };
                DataAccessHelper dbHelper = new DataAccessHelper();
                dbHelper.AddDepartment(department);
                var addedDepartment = dbHelper.FetchDepartments().FirstOrDefault();
                if (addedDepartment != null)
                {
                    Console.WriteLine("Department Name is: " + 
                                       addedDepartment.DepartmentName + Environment.NewLine);
                    Console.WriteLine("Department Employees are: " + Environment.NewLine);
    
                    foreach (var addedDepartmentEmployee in addedDepartment.Employees)
                    {
                        Console.WriteLine(addedDepartmentEmployee.EmployeeName + Environment.NewLine);
                    }
    
                    Console.ReadLine();
                }
            }
        }
    }

    In the above code of Main() method, we are trying to create an object of Department class and add a list of Employees to the Employees property of that class. Create an instance of the dbHelper class and invoke the method AddDepartment, passing the department entity object to that method to add the new department.

    Just after adding the department, we are fetching the newly added department and just to make sure that the department and its related employees got added successfully to the database. So, we’ll fetch the departments and on the console, print the department name and its related employees. But how will all this be done, we do not have a database yet. ☹

  11. Not to worry, let’s see how we can make sure that we get the DB created from our code. First, like we saw earlier, our context class name should be the same as our connection string name or vice versa. So, add a connection string having the same name as DB context class in the App.config file as shown below:

    Image 14

    Job done! Entity Framework will take care of rest of the pending work of creating a database. We just run the application and now, DB context class is first used to perform a DB operation, we get our database created.

  12. Put a breakpoint on the main method and run the application.

    Image 15

  13. As soon as the line where we write the code to AddDepartment gets executed, our database is created.

    Image 16

  14. Go to the database server and see that we got the database created with the same name that we supplied in the connection string. We have Departments and Employees table and a table named __MigrationHistory to track the history of code first migrations performed on this database.

    Image 17

    We see that we also got one Department added in the database having the name ”Technology” that we used in the code.

    Image 18

    And, got our employee's table filled with three rows having three employees with department id 1, i.e., the id of the newly added department. And so our code first approach worked as well. 😊

    Image 19

  15. You can proceed to press F5, to run the application and when console window appears, we see the details of the department and added employees in that window, so our fetch operations also work fine.

    Image 20

Though we covered all the approaches of the entity framework, I would like to show the code first migrations as well now to make you understand how to code first migrations work with entity framework. Before that, we need to know what is the requirement of migrations and what is the benefit of having migrations while working with code first approach.

Code First Options

The entity framework code first approach provides us with three approaches while creating the database.

CreateDatabaseIfNotExists

It is the option provided as an initializer class for code first approach. This helps us create a database only if there is no existing database and so any accidental dropping of that could be via this option.

DropCreateDatabaseWhenModelChanges

This initializer class keeps an eye on the underlying model and if the model changes, it drops the existing database and re-creates a new one. It is useful when the application is not live and the development and testing phase is going on.

DropCreateDatabaseAlways

This option as the name says always drops and creates a database whenever you run the application. It is most useful in testing when you are testing with the new set of data every time.

Code First Migrations

Imagine a scenario where you want to add a new model/entity and you do not want the existing database to get deleted or changed when you update the database with the newly added model class. Code first migrations here help you to update the existing database with your newly added model classes and your existing database remains intact with the existing data. So, the data and schema won’t be created again.

Code First Migrations in Action

Let’s see how we can work with code first migrations step by step like we did for other approaches.

  1. Add a new console application named EF_CF_Migrations.

    Image 21

  2. Add the Department model with properties DepartmentId, DepartmentName and DepartmentDescription. Add a virtual property as a navigation property called Employees because a department can have multiple employees.

    Image 22

  3. Similarly, add a model class named Employee and add three properties as EmployeeId, EmployeeName, DepartmentId, and Departments as a navigation property as an employee may be associated with any department.

    Image 23

  4. Install Entity Framework from the package manager console as shown in the following image:

    Image 24

  5. Add a context class deriving from DbContext class and add Employee and Department class as a DbSet property in the class.

    Image 25

  6. Now, execute command named “Enable-Migrations” but before that, select the default project as your newly added project. The command has to be executed using the package manager console.

    Image 26

  7. Once the command is executed, you’ll get a folder in your application named “Migrations” and by default, a class named Configuration would be added that holds your initial configurations and all other configurations you want to have with code first approach. You can configure the settings in the constructor of this class. This class derives from DbMigrationsConfigurations which has a virtual method Seed in the base class. We can override the method in our derived class to add some seed data to our database when it gets created.

    Image 27

  8. The Seed method takes the context as a parameter. Context is the instance of our CodeFirstContext class. Now add sample data to the context, for e.g., as shown below, I am adding one department named Technology with three sample employees and one additional employee separately to the context. The class will look similar to the code below:
    C#
    using System.Collections.Generic;
    
    namespace EF_CF_Migrations.Migrations
    {
        using System;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
    
        internal sealed class Configuration : 
                  DbMigrationsConfiguration<EF_CF_Migrations.CodeFirstContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(EF_CF_Migrations.CodeFirstContext context)
            {
                Department department = new Department
                {
                    DepartmentName = "Technology",
                    Employees = new List<Employee>
                    {
                        new Employee() {EmployeeName = "Jack"},
                        new Employee() {EmployeeName = "Kim"},
                        new Employee() {EmployeeName = "Shen"}
                    }
                };
    
                Employee employee = new Employee
                {
                    EmployeeName = "Akhil Mittal",
                    DepartmentId = 1
                };
    
                context.Departments.AddOrUpdate(department);
                context.Employees.AddOrUpdate(employee);
            }
        }
    }

    Image 28

  9. Now execute one more command that says “Add-Migration Initial” on package manager console. This command, when executed, creates one more file under the Migrations folder.

    Image 29

    The name of the file comprises the stamp and is with the keyword “_Initial”. This class derives from DbMigration class that has a virtual Up() method. The command overrides this method in the generated class and adds statements to create the database tables when our code will execute. The Down() method is the opposite of the Up() method.

    Image 30

    Following is the code that got generated for us when we added the initial migration. The Up method holds the database statements and takes care of key constraints as well while creating tables in the database.

    C#
    namespace EF_CF_Migrations.Migrations
    {
        using System;
        using System.Data.Entity.Migrations;
       
        public partial class Initial : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Departments",
                    c => new
                        {
                            DepartmentId = c.Int(nullable: false, identity: true),
                            DepartmentName = c.String(),
                            DepartmentDescription = c.String(),
                        })
                    .PrimaryKey(t => t.DepartmentId);
               
                CreateTable(
                    "dbo.Employees",
                    c => new
                        {
                            EmployeeId = c.Int(nullable: false, identity: true),
                            EmployeeName = c.String(),
                            DepartmentId = c.Int(nullable: false),
                        })
                    .PrimaryKey(t => t.EmployeeId)
                    .ForeignKey("dbo.Departments", t => t.DepartmentId, cascadeDelete: true)
                    .Index(t => t.DepartmentId);           
            }
           
            public override void Down()
            {
                DropForeignKey("dbo.Employees", "DepartmentId", "dbo.Departments");
                DropIndex("dbo.Employees", new[] { "DepartmentId" });
                DropTable("dbo.Employees");
                DropTable("dbo.Departments");
            }
        }
    }
  10. There still is a gap that needs to be bridged before we proceed. We’ll need to have a connection string with the same name as of our context class in our App.config. So open the app.config file of the project and add the connection string as needed with the server and database name details.

    Image 31

  11. The last step of migrations is to execute a command that says “Update-Database”.

    Image 32

    This command, when executed on package manager console, applies all the migrations we have under the Migrations folder and runs the seed method of Configuration class.

    Image 33

  12. Now, go to the database to check if we got our tables created or not with the sample data that we provided in seed method. In the image below, we see the Departments table having the sample department that we added in seed method to context as Department model.

    Image 34

    In the Employees, we have all the employees associated with that department and one additional employee as well that we added via seed method.

    Image 35

  13. Let’s add some code to our program.cs class to check if the database operations are working fine or not. So, create an instance of CodeFirstContext and add one more sample department with sample employees and save the changes.

    Image 36

    Following is the code:

    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF_CF_Migrations
    {
        class Program
        {
            static void Main(string[] args)
            {
                CodeFirstContext context =new CodeFirstContext();
    
                Department department = new Department
                {
                    DepartmentName = "Management",
                    Employees = new List<Employee>
                    {
                        new Employee() {EmployeeName = "Hui"},
                        new Employee() {EmployeeName = "Dui"},
                        new Employee() {EmployeeName = "Lui"}
                    }
                };
                context.Departments.Add(department);
                context.SaveChanges();
            }
        }
    }
  14. Run the code by pressing F5 and then go to the database to check if the records for department and Employees associated with it got inserted or not. We see in the following image while selecting top records from Departments table, we get one additional department that we just created.

    Image 37

    • We get added Employees for the newly added department as shown in the following image:

      Image 38

MigrationHistory Table

This is the most important part of code first migrations. We see that along with our entity tables, we got an additional table named __MigrationHistory. This table takes responsibility to hold all the migrations history that we add from code. For example, check the row that it got initially. The MigrationId column of the first row contains the value that is the same as the name of the file that got created when we added migrations in our code. It contains the hash and every time we add or modify something in the model and run update migrations command, it checks the history in the database and compares with the existing files of migrations that we have in our Migrations folder. If the file is new, it executes that file only and not the old ones. This helps us to track database changes in the more organized way. One can also revert back to a particular migration from code by supplying the migration id of that migration. Migration id is nothing but the name of the migration file and the same that got stored in the __MigrationHistory table as the column value. The following two images show that the column value in the MigrationHistory table and the file name in the code for migration is similar.

Image 39

Image 40

In case you add a new migration, a new file would be created with a unique name having stamp and when you run update migration, a new row will be inserted the __MigrationHistory table for the same having same column as the name of the added file.

Image 41

Conclusion

In this, we closely saw how we can leverage Entity Framework’s code first approach and as per need, use those. I took the basic console application to explain the concept, but these could be used in any enterprise level application that uses WebAPIs, ASP.NET projects or MVC projects as well. We closely looked into code first migrations and importance of migrations table as well. Download the complete free eBook (Diving into Microsoft .NET Entity Framework) on Entity Framework here.

License

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


Written By
Architect https://codeteddy.com/
India India
Akhil Mittal is two times Microsoft MVP (Most Valuable Professional) firstly awarded in 2016 and continued in 2017 in Visual Studio and Technologies category, C# Corner MVP since 2013, Code Project MVP since 2014, a blogger, author and likes to write/read technical articles, blogs, and books. Akhil is a technical architect and loves to work on complex business problems and cutting-edge technologies. He has an experience of around 15 years in developing, designing, and architecting enterprises level applications primarily in Microsoft Technologies. He has diverse experience in working on cutting-edge technologies that include Microsoft Stack, AI, Machine Learning, and Cloud computing. Akhil is an MCP (Microsoft Certified Professional) in Web Applications and Dot Net Framework.
Visit Akhil Mittal’s personal blog CodeTeddy (CodeTeddy ) for some good and informative articles. Following are some tech certifications that Akhil cleared,
• AZ-304: Microsoft Azure Architect Design.
• AZ-303: Microsoft Azure Architect Technologies.
• AZ-900: Microsoft Azure Fundamentals.
• Microsoft MCTS (70-528) Certified Programmer.
• Microsoft MCTS (70-536) Certified Programmer.
• Microsoft MCTS (70-515) Certified Programmer.

LinkedIn: https://www.linkedin.com/in/akhilmittal/
This is a Collaborative Group

779 members

Comments and Discussions

 
Questioncode first works only once Pin
tshad16-Mar-21 15:20
tshad16-Mar-21 15:20 
PraiseNice Pin
devanganaa6-Feb-19 3:51
devanganaa6-Feb-19 3:51 
QuestionThere is already an object named 'Departments' in the database. Pin
MassimoMichele16-Oct-18 4:32
MassimoMichele16-Oct-18 4:32 
AnswerRe: There is already an object named 'Departments' in the database. Pin
Akhil Mittal18-Oct-18 1:44
professionalAkhil Mittal18-Oct-18 1:44 
GeneralRe: There is already an object named 'Departments' in the database. Pin
MassimoMichele18-Oct-18 4:04
MassimoMichele18-Oct-18 4:04 
GeneralMy vote of 5 Pin
Member 130030644-Oct-18 9:09
Member 130030644-Oct-18 9:09 
GeneralRe: My vote of 5 Pin
Akhil Mittal4-Oct-18 23:46
professionalAkhil Mittal4-Oct-18 23:46 
PraiseThank you very much Pin
Member 120031023-Oct-18 2:59
Member 120031023-Oct-18 2:59 
GeneralRe: Thank you very much Pin
Akhil Mittal3-Oct-18 4:33
professionalAkhil Mittal3-Oct-18 4:33 
Thanks Smile | :)
Thanks
Happy Coding Smile | :)

Praisenice! Pin
Eddy Sels2-Oct-18 3:11
professionalEddy Sels2-Oct-18 3:11 
GeneralRe: nice! Pin
Akhil Mittal3-Oct-18 0:00
professionalAkhil Mittal3-Oct-18 0:00 
GeneralRe: nice! Pin
Akhil Mittal3-Oct-18 0:01
professionalAkhil Mittal3-Oct-18 0:01 
GeneralMy vote of 5 Pin
D V L1-Oct-18 1:45
professionalD V L1-Oct-18 1:45 
GeneralRe: My vote of 5 Pin
Akhil Mittal3-Oct-18 0:00
professionalAkhil Mittal3-Oct-18 0:00 
GeneralRe: My vote of 5 Pin
Akhil Mittal3-Oct-18 0:01
professionalAkhil Mittal3-Oct-18 0:01 
GeneralMy vote of 5 Pin
Wooters30-Sep-18 7:27
Wooters30-Sep-18 7:27 
GeneralRe: My vote of 5 Pin
Akhil Mittal30-Sep-18 22:23
professionalAkhil Mittal30-Sep-18 22:23 
PraiseMy vote of 5 Pin
Vikas Sharma28-Sep-18 21:07
professionalVikas Sharma28-Sep-18 21:07 
GeneralRe: My vote of 5 Pin
Akhil Mittal28-Sep-18 22:09
professionalAkhil Mittal28-Sep-18 22:09 
GeneralRe: My vote of 5 Pin
Akhil Mittal3-Oct-18 0:02
professionalAkhil Mittal3-Oct-18 0:02 
GeneralNo Images Pin
Klaus Luedenscheidt28-Sep-18 18:52
Klaus Luedenscheidt28-Sep-18 18:52 
GeneralRe: No Images Pin
Akhil Mittal28-Sep-18 22:03
professionalAkhil Mittal28-Sep-18 22:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.