In the article three approaches of Entity framework we have already discussed, how to create domain model using code-first workflow, this article is just a recap of the part where we had discussed to create domain model using code-first workflow, just for that audience who are directly landing here
.To create a domain model with code-first workflow we simply follow 9 steps as shown in below diagram.
if you are not dealing with multiple tables , then obviously, you don't need to worry about navigation properties, Foreign keys and Relationships so you can skip step 2,3,4 and 5. so Let's get started.
Step 1. Go to Visual Studio and create a new console application , Name it as CodeFirstDemo.
Step 2.Similar to Database-First workflow , as it is a new project we need to install Entity Framework First. To do that , we use package manager console.
• Go to Tools.
• Then, go to Nuget Package Manger and select Package Manager Console.
• Install Entity Framework using the install-package command.
Install-Package EntityFramework -Version 6.2.0
Step 3. Now, with the Code-First of Course we start with the code , so we do not need to go to Management Studio and create tables , instead here we create our domain classes all by ourselves. so, Add two class Files in your project with the name of Employee and Department respectively, with their own properties only, as shown in below code.
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
Step 4. Now add the navigation properties, so that we could easily navigate from one entity to a related entity. To add navigation properties, think about the real-world relationship between an Employee and Department.
• Department has multiple Employees ( so, Department entity should contain a collection of Employee as its property)
• Employee belongs to a single Department only( so, Employee entity should contain a Department property)
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public Department Department { get; set; }
}
Step 5. Add Foreign-Key properties to Entities.
An Employee Entity must have a DepartmentId property as a foreign key. Actually it is not necessary to define a foreign key property because Entity Framework is smart enough to generate foreign keys by analyzing the association between tables with the help of Navigation properties we defined in previous step but it is always a good practice to explicitly define foreign keys and to override the convention.
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int DepId { get; set; }
public Department Department { get; set; }
}
Step 6. Establish a relationship between tables.
Yes we have already defined foreign key properties and Navigation properties but we did not tell it to Entity framework anywhere that which property is a foreign key, to establish a relationship correctly we can either use data-annotations or Fluent-API. for now I am going to use data-annotation, later we will discuss to use Fluent API.
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Department")] // look at this
public int DepId { get; set; }
public Department Department { get; set; }
}
Note: here we are just letting the Entity framework know that DepId in Employee entity is a foreign Key and is related to primary key of Department Entity by passing the Department as parameter.
Notice the class looks exactly the same as the one EF generated for us as a part of Database-First work Flow , but here we have created it by hand. Each employee belongs to a Department so we use Department as a property in Employee Class , similarly a Department can have multiple Employees so we have used ICollection of Employee. This is needed for the association , we will discuss more about relationship and association in our later article.
Step 7. Now, In Companion to our Domain Classes we also need a DbContextClass , so that we could interact with the database later in our project.
Basically we have to create a class which derives DbContextand exposes one or more DbSet . In our case, DbSet of Employee and Department.
So , add a new class file and Name it as OrganizationDbContextand copy -paste the below code.
public class OrganizationDbContext:DbContext
{
public DbSet Employees { get; set; }
public DbSet Departments { get; set; }
}
Step 8. Next , we need to specify the connection string , so that EF could connect to server and generate database and tables for us.
Go to App.config and add a connection String, name it as the name of your DbContext , because EF works on convention over configuration. It recognizes the connection string by its name.
<connectionStrings>
<connectionStrings>
<add name="OrganizationDbContext" connectionString="Data Source=SACHIN-PC\SQLEXPRESS;Initial Catalog=OrganizationDB;Integrated Security=True" providerName="System.Data.SqlClient"/>
if you want to give connection string a different name than your DbContext Name then you will have to configure it using base constructor of DbContext class as shown below.
<connectionStrings>
<connectionStrings>
<add name="myConnectionString" connectionString="Data Source=SACHIN-PC\SQLEXPRESS;Initial Catalog=OrganizationDB;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
public class OrganizationDbContext:DbContext
{
public OrganizationDbContext ()
: base("myConnectionString")
{
}
public DbSet Employees { get; set; }
public DbSet Departments { get; set; }
}
Please Notice , here we have explicitly specified one additional property to the connection string that is provider name as Sytem.Data.SqlClient. This is required to work with code First workflow.
Step 9. Next we need to go to package Manager console and Enable Migrations. This is the code that we run once for the life time of the project.
PM> Enable-Migrations
Notice , a migration folder has been added to our project.
Step 10. Next we need to add a migration . Go to your Package Manager Console and use Command Add-Migration and give it a meaningful name based on the changes you have made to your model class. It is our first migration so we simply name it as AddedEmployeeAndDepartment.
PM> Add-Migration AddedEmployeeAndDepartment
Notice:- Under Migration folder a new migration file has been created , the name is a combination of date time stamp and description , which is very similar to our change script that we had created to keep track of changes in our database and to manage different versions of it while working with database-first workflow. In Database-First work flow we had created that manually but here we did the same but in more automated fashion.
Step 9. Run the migration against database . To run the migration go to package manager console and run below code.
PM> update-database
when we run the migration , the EF looks at our database and figures out which migration it needs to run on the server to bring it up to date , it converts the migration into SQL code and runs against the server.
Now , let's see the results , Go back to SSMS and Notice EF has created a Database OrganizationDb based on the name of database we had specified in the connectionstring , notice along with the table it also created a MigrationHistory object , so that it could run it on server whenever it needs. The table structure looks exactly the same as we had created manually while working with database first approach.
How to manage database changes
After adding or modifying anything in database we just need to open package manager console and
• Add a new migration using add-migration command and then
• Run that migration using update-database command
How to manage different versions of the application with Code First work Flow
This is where code-First workflow rocks, Remember in the database-First workflow to manage different versions of the database we had created the change script manually, but with Code-First workflow we get it automatically in the form of Migrations, we can run up to any migration anytime to bring the database up to that version.
Unfolding Migration Folder
A migration Folder contains two things
1. A configuration folder, which is used to configure the association between tables using Fluent API and To seed the database, which we will discuss in later articles.
2. The actual migration files.
Let's check what does a Migration.cs file contain.
public partial class AddedEmployeeAndDepartment : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Departments",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Employees",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
DepId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Departments", t => t.DepId)
.Index(t => t.DepId);
}
public override void Down()
{
DropForeignKey("dbo.Employees", "DepId", "dbo.Departments");
DropIndex("dbo.Employees", new[] { "DepId" });
DropTable("dbo.Employees");
DropTable("dbo.Departments");
}
}
1. The name of the migration class is what we specify while adding the migration using the package manager console.
2. Surprisingly enough it doesn't contain any SQL query rather it contains two methods with plain c# code.
3. The Up() method simply contains the changes that we do in our Context class or Domain models.
4. The Down() method contains the opposite of whatever is there in Up() method.
5. Notice EF uses convention over configuration so the column with the Name Id automatically becomes the primary key for the table not only this EF makes it an Identity column as well.
6. In simple terms when EF looks at our model classes then based on the Name and the Type of properties, it figures out how the database should look like for example it knows that Id is typically used for the primary key, and often it is an identity column so it automatically marks the column as Identity, similarly based on Association, aggregation, and composition it automatically adds the required foreign keys.
How to manage changes in domain Model or Context Class
whenever we make a change in Context Class or Domain Classes ,we just need to add a new Migration using Add-Migration command and run it against the database by using the update-database command , we obviously use package manager console to run these commands.
The Steps that we perform only once throughout the life time of the application development.
Installing Entity Framework and Enabling migrations require to perform only once in the life time of the application development.
How to DbContext to Add data to the database
The below steps applies to both database-First approach and Code-First Approach.
Step 1. Create an Instance of DbContext Class which in our case is OrganizationDbContext.
Step 2. Create a new Employee Object or Department Object.
Step 3. Add this object to the related DbSet object ,which represents an In-Memory collection of objects.
Step 4. Commit the changes to database usingDbContext SaveChanges() method.
static void Main(string[] args)
{
using (OrganizationDbContext db = new OrganizationDbContext())
{
var emp=new Employee()
{
Name="Sachin",
Department= new Department(){Name="HR"}
};
db.SaveChanges();
}
}
Notice : in the above example we have directly added Department object to Employee , on running the application the EF will Add a new record to Employee table as well as the Department table , this is the power of EF.
The above approach is used when you have no data in the other table , as we had no department in department table so we used the above approach , now we have one department with Id=1 and Name as HR so to add other employee we can simply use DepartmentId of Employee as shown below.
static void Main(string[] args)
{
using (OrganizationDbContext db = new OrganizationDbContext())
{
var emp=new Employee()
{
Name="Michael",
DepId=1
};
db.Employees.Add(emp);
db.SaveChanges();
}
}