Entity Framework Code First Basic FAQ – Part 1

The Entity Framework (EF) with Code First is so popular that any database developer should own skills for this kind of development. If you make a search of EF with Code First, you’ll find tons of tutorial figuring out how it works and all things relevant. Therefore in this blog post, I don’t intend to give you something new, indeed there is nothing new. I just want to make a summary of all necessary basic steps when I start a project with EF Code First. So if you’re already professional with EF, just skip this post.

1. Create models

– As its name “Code First”, we have to write… code first. Let’s define our models.
– Create a new project and add some models for example


internal class Course
{
	public int Id { get; set; }

	public string Name { get; set; }

	public string Url { get; set; }

	public virtual List<Student> Students { get; set; }
}

class Student
{
	public int Id { get; set; }

	public string FirstName { get; set; }

	public string LastName { get; set; }

	public int CourseId { get; set; }

	public virtual Course Course { get; set; }
}

2. Create context

2.1 Install Nuget

– If you already installed Nuget, skip this step. If not, then download NuGet Package Manager from following link

http://visualstudiogallery.msdn.microsoft.com/27077b70-9dad-4c64-adcf-c7cf6bc9970c

and install it.

2.2 Install Entity Framework

– Right click on your project and choose “Manage NuGet Packages…”

Manage NuGet Packages

– On the new window, be sure that on the left “Online –> NuGet official package source” is selected. In the middle panel, click to install “EntityFramework”

EntityFramework install

2.3 Create context

– Now we have to define a derived context representing a session to database. Through this context we can make a query to select or to update data. A derived context must inherit System.Data.Entity.DbContext and expose a DbSet for each model. In our example the context looks like following

internal class CourseraContext : DbContext
{
 public DbSet<Course> Courses { get; set; }

public DbSet<Student> Students { get; set; }
}

– In code listing above, each model is exposed by a DbSet

3. Read and write data

– Let’s write some code for reading and writing data

private static void Main(string[] args)
{
	int option = -1;
	while (option != 0)
	{
		Console.WriteLine("Choose an option (0, 1, 2):" + Environment.NewLine +
			"1. Enter a course" + Environment.NewLine +
			"2. Enter a student" + Environment.NewLine +
			"3. List all courses" + Environment.NewLine +
			"4. List all students" + Environment.NewLine +
			"0. Exit" + Environment.NewLine);
		if (int.TryParse(Console.ReadLine(), out option))
		{
			switch (option)
			{
				case 1:
					EnterCourse();
					break;

				case 2:
					EnterStudent();
					break;

				case 3:
					ListAllCourses();
					break;

				case 4:
					ListAllStudents();
					break;
			}
		}
	}
	Console.WriteLine("Press any key to quit...");
	Console.ReadLine();
}

private static void ListAllStudents()
{
	throw new NotImplementedException();
}

private static void ListAllCourses()
{
	using (var db = new CourseraContext())
	{
		foreach (Course course in db.Courses)
			Console.WriteLine(string.Format("Course: {0} - {1}", course.Id, course.Name) + Environment.NewLine);
	}
}

private static void EnterStudent()
{
	throw new NotImplementedException();
}

private static void EnterCourse()
{
	string name = "";

	while (name != "0")
	{
		Console.WriteLine("Enter name of course (0 to exit):");
		name = Console.ReadLine().Trim();
		if (name != "0")
		{
			using (var db = new CourseraContext())
			{
				Course course = new Course();
				course.Name = name;
				db.Courses.Add(course);
				db.SaveChanges();
			}
		}
	}
}

– The code listing above provides a menu in console application where user can enter a course or students who participate in that course. User can also list all available courses in database. You know, just typical functions to show how code works. So let’s start the sample application and try to create a course then list all courses in database

Sample console application

4 Connection and database

– The sample application works like a charm without requiring us to define any database connection but we want to know where our database is, don’t we? By default convention, DbContext has created a database for us as following criterias:
+ If a local SQL Express instance is available then the database will be created on that instance.
+ If SQL Express instance isn’t available then LocalDb will be used if LocalDb is available.
+ If SQL Express and LocalDb are both availabe, SQL Express will be used.
+ The database is named after the namespace qualified name of the derived context, in our case that is EF_CodeFirst_Basic.DAO.CourseraContext

Default database name code first

4.1 Customize database name

– If you don’t like the default generated database name, you can specify an other name at default constructor of our derived context like following

internal class CourseraContext : DbContext
{
	public CourseraContext()
		: base("Coursera")
	{
	}

	public DbSet<Course> Courses { get; set; }

	public DbSet<Student> Students { get; set; }
}

4.2 Customize connection string

– If you would like to let the user specify the connection string as well as database name, you have to specify a default name of connection string in your derived DbContext and add one connection string setting with that name in app.config

internal class CourseraContext : DbContext
{
	public CourseraContext()
		: base("DefaultConnection")
	{
	}

	public DbSet<Course> Courses { get; set; }

	public DbSet<Student> Students { get; set; }
}

 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  </entityFramework>
  <connectionStrings>
    <add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Server=.\sqlexpress;Database=Coursera;Trusted_Connection=True;" />
  </connectionStrings>
</configuration>

5. Migrations

– So, the database is already created when we run the application. Now, if we make changes to our model, we also want to update the database schema. These update actions are called “migrations”. The migrations are the ordered sets of steps describing how the database schema must be upgraded/downgraded. Each of these steps, known as a migration, contains code that describes the changes to be applied.

5.1 InvalidOperationException

– Before we continue with migrations, I would like to show what happens when we change model without database schema changes. Let’s insert new Url property to model Course

internal class Course
{
	public int Id { get; set; }

	public string Name { get; set; }

	public string Url { get; set; }

	public virtual List<Student> Students { get; set; }
}

– Run the application and try to enter a course

InvalidOperationException

you’ll receive an error when application tries to save data to database because the model was changed meanwhile the database schema is still in old version

The model backing the ‘CourseraContext’ context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

5.2 Enable migrations

– To use feature Migration of Code First, we have to enable it by going to TOOLS –> Library Package Manager –> Package Manager Console

Package Manager Console

– Run Enable-Migrations command in Package Manager Console


Enable-Migrations

Enable-Migrations

– After the command is executed, a new folder Migrations will be created in project. This folder contains a _InitialCreate.cs and a Configuration.cs where
+ _InitialCreate.cs : is the first migration, it contains the changes that have already been applied to the database from an empty database to one that includes the Courses and Students tables. Although Code First already creates automatically the tables for us, the steps to create them have also been converted into a migration. However Code First has marked in database that this migration has already been applied. Therefore the application won’t try to create table again. The time stamp before file name is used for ordering purposes.
+ Configuration.cs : contains settings that migrations will use for migrating. Here is where you can specify seed data, register providers for other databases, changes the namespace that migrations are generated in…

_InitialCreate

5.3 Add migrations

– Now it’s time to make migration for new property Url of Course. In Package Manager Console, type in the command “Add-Migration AddUrlToCourse”


Add-Migration AddUrlToCourse

Add-Migration

– The Add-Migration command checks for changes since your last migration and scaffolds a new migration with any change found. AddUrlToCourse is the name of migration. After the command is executed, a new migration class with time stamp will be created.

public partial class AddUrlToCourse : DbMigration
{
	public override void Up()
	{
		AddColumn("dbo.Courses", "Url", c => c.String());
	}

	public override void Down()
	{
		DropColumn("dbo.Courses", "Url");
	}
}

– The generated code of the migration adds new column whose type is string and name is Url.

5.4 Update database

– Although the migration was created, we need to explicit update database by calling Update-Database in Package Manager Console


Update-Database

Update-Database

– This command will apply any pending migrations to the database. Our InitialCreate migration has already been applied so Update-Database will just apply new AddUrlToCourse migration. Check the database schema in Management Studio, you’ll see new column Url is inserted.

Update-Database

– This command also supports parameters such as Verbose, Script or TagetMigration
+ Verbose: all running SQL queries against database will be shown

Update-Database -Verbose

+ Script: the SQL queries won’t be applied to database but will be generated to new window so that user can apply the migrations outside the application.

Update-Database script

+ TargetMigration: specifies to which migration we would like to bring database schema to. If you want to reset to empty database, you can run the command “Update-Database –TargetMigration: $InitialDatabase”.


Update-Database –TargetMigration: $InitialDatabase

Update-Database TargetMigration

5.5 Update to latest migration with code

– If you want to always update database schema to latest migration when the application starts, use this code listing at program’s start-up.

Database.SetInitializer(new MigrateDatabaseToLatestVersion<CourseraContext, Configuration>());

6. Data annotations

– So far we’ve just let EF discover the model using its default conventions, but if our classes don’t follow the conventions, error will come and we need to perform further configuration. Add a new class Teacher to our sample

internal class Teacher
{
	public string UserName { get; set; }

	public string FirstName { get; set; }

	public string Lastname { get; set; }
}

internal class CourseraContext : DbContext
{
	public CourseraContext()
		: base("name=DefaultConnection")
	{
	}

	public DbSet<Course> Courses { get; set; }

	public DbSet<Student> Students { get; set; }

	public DbSet<Teacher> Teachers { get; set; }
}

– Try to add migration for creating this model in database “Add-Migration AddTeacher”.


Add-Migration AddTeacher

You will encounter an error like “EntityType ‘Teacher’ has no key defined. Define the key for this EntityType”

EntityType has no key defined

– To solve this problem, you can use data annotations to define a primary key. For example, we can use UserName as primary key for Teacher class by adding KeyAttribute annotation to it.


internal class Teacher
{
 [Key]
 public string UserName { get; set; }

public string FirstName { get; set; }

public string Lastname { get; set; }
}

– Try to Add-Migration again, it works now. Entity Framework does support other annotation attributes (such as MaxLength, Phone, Url…) you can find the others at following link http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx

7. Fluent API

In the previous section we use data  annotations to supplement or to override what was detected by convention.Most model configuration can be done using simple data annotations. However there is still the other way to configure the model, that is via the Code First Fluent API. The fluent API is a more advanced way of specifying model configuration that covers everything that data annotations can do. Fluent API is in addition to some more advanced configuration not possible with data annotations. Data annotations and the fluent API can be used together.

To access the fluent API, you override the OnModelCreating method in DbContext. For example, we want to rename the column UserName of Teacher table into “Id”. Override the OnModelCreating method on with the following code

internal class CourseraContext : DbContext
{
	public CourseraContext()
		: base("name=DefaultConnection")
	{
	}

	public DbSet<Course> Courses { get; set; }

	public DbSet<Student> Students { get; set; }

	public DbSet<Teacher> Teachers { get; set; }

	protected override void OnModelCreating(DbModelBuilder modelBuilder)
	{
		modelBuilder.Entity<Teacher>()
			.Property(u => u.UserName)
			.HasColumnName("Id");
	}
}

– Add-Migration for applying changes to database schema


Add-Migration ChangeTeacherUserNameColumn

Fluent Api to rename column

8. Summary

In this post we had learnt some basic steps with Code First development using new database. With these basic steps we can build up a professional database application without writing any complex SQL query.
Source code: https://bitbucket.org/hintdesk/dotnet-entity-framework-code-first-basic-faq

3 thoughts on “Entity Framework Code First Basic FAQ – Part 1”

Leave a Reply

Your email address will not be published. Required fields are marked *