You will need to have Visual Studio 2010 or Visual Studio 2012 installed to complete this walkthrough.
If you are using Visual Studio 2010, you will also need to have NuGet installed.
To keep things simple we’re going to build a basic console application that uses Code First to perform data access.
Let’s define a very simple model using classes. We’re just defining them in the Program.cs file but in a real world application you would split your classes out into separate files and potentially a separate project.
Below the Program class definition in Program.cs add the following two classes.
public class Blog { public int BlogId { get; set; } public string Name { get; set; } public virtual List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public virtual Blog Blog { get; set; } }
You’ll notice that we’re making the two navigation properties (Blog.Posts and Post.Blog) virtual. This enables the Lazy Loading feature of Entity Framework. Lazy Loading means that the contents of these properties will be automatically loaded from the database when you try to access them.
Now it’s time to define a derived context, which represents a session with the database, allowing us to query and save data. We define a context that derives from System.Data.Entity.DbContext and exposes a typed DbSet<TEntity> for each class in our model.
We’re now starting to use types from the Entity Framework so we need to add the EntityFramework NuGet package.
Add a using statement for System.Data.Entity at the top of Program.cs.
using System.Data.Entity;
Below the Post class in Program.cs add the following derived context.
public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } }
Here is a complete listing of what Program.cs should now contain.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.Entity; namespace CodeFirstNewDatabaseSample { class Program { static void Main(string[] args) { } } public class Blog { public int BlogId { get; set; } public string Name { get; set; } public virtual List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public virtual Blog Blog { get; set; } } public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } } }
That is all the code we need to start storing and retrieving data. Obviously there is quite a bit going on behind the scenes and we’ll take a look at that in a moment but first let’s see it in action.
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 Blog. Then it uses a LINQ query to retrieve all Blogs from the database ordered alphabetically by Title.
class Program { static void Main(string[] args) { using (var db = new BloggingContext()) { // Create and save a new Blog Console.Write("Enter a name for a new Blog: "); var name = Console.ReadLine(); var blog = new Blog { Name = name }; db.Blogs.Add(blog); db.SaveChanges(); // Display all Blogs from the database var query = from b in db.Blogs orderby b.Name select b; Console.WriteLine("All blogs in the database:"); foreach (var item in query) { Console.WriteLine(item.Name); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } } }
You can now run the application and test it out.
Enter a name for a new Blog: ADO.NET Blog All blogs in the database: ADO.NET Blog Press any key to exit... |
By convention DbContext has created a database for you.
These are just the default conventions and there are various ways to change the database that Code First uses, more information is available in the How DbContext Discovers the Model and Database Connection topic.
You can connect to this database using Server Explorer in Visual Studio
We can now inspect the schema that Code First created.
DbContext worked out what classes to include in the model by looking at the DbSet properties that we defined. It then uses the default set of Code First conventions to determine table and column names, determine data types, find primary keys, etc. Later in this walkthrough we’ll look at how you can override these conventions.
Now it’s time to make some changes to our model, when we make these changes we also need to update the database schema. To do this we are going to use a feature called Code First Migrations, or Migrations for short.
Migrations allows us to have an ordered set of steps that describe how to upgrade (and downgrade) our database schema. Each of these steps, known as a migration, contains some code that describes the changes to be applied.
The first step is to enable Code First Migrations for our BloggingContext.
public class Blog { public int BlogId { get; set; } public string Name { get; set; } public string Url { get; set; } public virtual List<Post> Posts { get; set; } }
namespace CodeFirstNewDatabaseSample.Migrations { using System; using System.Data.Entity.Migrations; public partial class AddUrl : DbMigration { public override void Up() { AddColumn("dbo.Blogs", "Url", c => c.String()); } public override void Down() { DropColumn("dbo.Blogs", "Url"); } } }
The new Url column is now added to the Blogs table in the database:
So far we’ve just let EF discover the model using its default conventions, but there are going to be times when our classes don’t follow the conventions and we need to be able to perform further configuration. There are two options for this; we’ll look at Data Annotations in this section and then the fluent API in the next section.
public class User { public string Username { get; set; } public string DisplayName { get; set; } }
public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } public DbSet<User> Users { get; set; } }
using System.ComponentModel.DataAnnotations;
public class User { [Key] public string Username { get; set; } public string DisplayName { get; set; } }
The new table is now added to the database:
The full list of annotations supported by EF is:
In the previous section we looked at using Data Annotations to supplement or override what was detected by convention. The other way to configure the model is via the Code First fluent API.
Most model configuration can be done using simple data annotations. The fluent API is a more advanced way of specifying model configuration that covers everything that data annotations can do 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. Let’s say we wanted to rename the column that User.DisplayName is stored in to display_name.
public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } public DbSet<User> Users { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<User>() .Property(u => u.DisplayName) .HasColumnName("display_name"); } }
The DisplayName column is now renamed to display_name:
In this walkthrough we looked at Code First development using a new database. We defined a model using classes then used that model to create a database and store and retrieve data. Once the database was created we used Code First Migrations to change the schema as our model evolved. We also saw how to configure a model using Data Annotations and the Fluent API.