Table of Contents
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.
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.
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.
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.
- Create a new console application named
EF_CF
. This will give you Program.cs and a Main()
method inside that.
- 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
.
- Similarly, add a new class named
Department
and add properties DepartmentId
, DepartmentName
, and DepartmentDescription
as shown below:
- 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.
- 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.
- 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:
The final code may look like:
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; }
}
}
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
.
- 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.
- 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.
The code may look like shown below:
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;
}
}
}
- 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.
Following is the code for the Employee
and the Department
model.
Employee
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
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; }
}
}
- 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:
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 department
s 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. ☹
- 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:
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.
- Put a breakpoint on the
main
method and run the application.
- As soon as the line where we write the code to
AddDepartment
gets executed, our database is created.
- 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.
We see that we also got one Department
added in the database having the name ”Technology
” that we used in the code.
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. 😊
- 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.
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.
The entity framework code first approach provides us with three approaches while creating the database.
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.
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.
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.
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.
Let’s see how we can work with code first migrations step by step like we did for other approaches.
- Add a new console application named
EF_CF_Migrations
.
- 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
.
- 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
.
- Install Entity Framework from the package manager console as shown in the following image:
- Add a
context
class deriving from DbContext
class and add Employee
and Department
class as a DbSet
property in the class.
- 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.
- 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.
- 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:
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);
}
}
}
- 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.
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.
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.
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");
}
}
}
- 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.
- The last step of migrations is to execute a command that says “
Update-Database
”.
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.
- 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.
In the Employees
, we have all the employees
associated with that department
and one additional employee
as well that we added via seed
method.
- 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.
Following is the code:
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();
}
}
}
- 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.
- We get added
Employees
for the newly added department
as shown in the following image:
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.
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.
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.