Introduction
In this article we will discuss about entity framework code first approach. We will see what are the benefits of code first approach. We will also create a sample
ASP.NET MVC application using code first approach.
Background
Before starting this article we need to understand the shift in the way the modern applications are being architectured. Traditionally we have been designing and
developing data centric applications(Data Driven Design)
. What this means is that we used to think about what data is required to fulfill our business needs and then we build our software bottom up
from the database schema. This approach is still being followed for many applications and for such applications we should use the Entity framework database first approach.
The alternative way of designing or architecturing our application is by using Domain centric approach(Domain Driven Design)
. In this approach we think in terms of entities and models
that we needed to solve a particular business problem. Now if some of these models need persistence we can keep them in a database or any data store. In this approach we design our
models in such a way that they can be stored/persisted anywhere. In other words we create persistent ignorant models and write persistence logic separately. Entity framework code first approach
is for creating application's models using Domain centric approach and then they can be persisted later.
So Entity framework code first approach enables us to write Plain Old CLR Objects(POCOs)
for our models and then let us persist them in a data store by defining a DbContext
class for our model classes.
Few of the benefits of using this approach are:
- Ability to support domain driven design.
- Ability to start development faster(without waiting for the database and to be ready and mature).
- Model classes are lot cleaner since there is no(or very minimal) persistence related code in the models.
- The persistence layer can be changed without having any impact on the models.
Note: This article is meant for the absolute beginner's who have never worked with the code first approach or who are unaware of this approach. So the article only contains the introductory information
and code to explain the concept and get the reader started. This article will not be discussing the advanced topics and best practices related to code first approach.
Using the code
Let us try to understand how we can implement the code first approach by creating a small toy application. The application that we will be creating is a small books information website which will
- Show a list of books.
- Show the details of selected book.
- Adding new books.
- Deleting Books.
- Editing books information.
- Users should also be able to add review comments for any given book.
Based on the above problem definition we need 2 models. One for Book
and another for the Reviews
. To get started lets go ahead and add a nuget
package reference to the Entity framework.
Now we are all set to start work on our application.
Creating the POCOs
Let us now go ahead and create these models without worrying about the persistence.
public class Book
{
public int BookID { get; set; }
public string BookName { get; set; }
public string ISBN { get; set; }
}
public class Review
{
public int ReviewID { get; set; }
public int BookID { get; set; }
public string ReviewText { get; set; }
}
In our Model classes we have defined the properties that we want to keep in our models. But there are few things which we have not done so far. There is a one to many relationship
between these models. So we need to take that into account for our models. Also, If we want to hint the database generation module about the persistence information like table names, key columns etc.
We can do that too in our model classes. So with these changes our model classes will look like.
[Table("Books")]
public class Book
{
[Key]
public int BookID { get; set; }
public string BookName { get; set; }
public string ISBN { get; set; }
public virtual ICollection<Review> Reviews { get; set; }
}
[Table("Reviews")]
public class Review
{
[Key]
public int ReviewID { get; set; }
[ForeignKey("Book")]
public int BookID { get; set; }
public string ReviewText { get; set; }
public virtual Book Book { get; set; }
}
Creating the Context class
Now we have our model classes ready. Next we need to create a DBContext
object that will be responsible for performing all the CRUD operations on these models. Let us go ahead and
create the DBContext
class for these models.
public class BooksDbContext : DbContext
{
public DbSet<Book> Books { get; set; }
public DbSet<Review> Reviews { get; set; }
}
The above defined context class is capable of performing CRUD operations on Book
and Review
model since it has the DbSet
defined for both of them.
Setting the database and location
Now with the DbContext class ready the
only question left for us that where this data will get stored. Since ages, we have been using ConnectionStrings
to specify the connection to the database. In this case also we can use
ConnectionString
too to specify the location and meta data of the database that the
DbContext
class should use. Let us see if we need to create the database in the App_Data folder, how the
ConnectionString
will look like:
<connectionStrings>
<add name="BooksDbContext" connectionString="data source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\sampleDb.mdf;integrated security=True;user instance=True;multipleactiveresultsets=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
The important thing to notice here is that the name of the connectionString
is same as the DbContext
class that we have created. If we keep the name of the connectionString
same as the DbContext
class the
corresponding DbContext
class will use the connectionString
to persist the data. This is on the lines of "Convention over configurations". But this is also flexible so that we have the possiblity of giving custom
names to the connectionStrings i.e. If we need to give any other name to the connectionString
or use some
already defined connectionString
with the DbContext
class then we need to pass the connectionString
name in the base class constructor of our DbContext
class.
Testing the Code first Models and Context
To test the above defined models let us create a simple ASP.NET MVC controller that will perform the CRUD operations on the Book
entity.
public class BooksController : Controller
{
BooksDbContext context = new BooksDbContext();
public ActionResult Index()
{
List<book> books = context.Books.ToList();
return View(books);
}
public ActionResult Details(int id)
{
Book book = context.Books.SingleOrDefault(b => b.BookID == id);
if (book == null)
{
return HttpNotFound();
}
return View(book);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Book book)
{
if (ModelState.IsValid)
{
context.Books.Add(book);
context.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
public ActionResult Edit(int id)
{
Book book = context.Books.Single(p => p.BookID == id);
if (book == null)
{
return HttpNotFound();
}
return View(book);
}
[HttpPost]
public ActionResult Edit(int id, Book book)
{
Book _book = context.Books.Single(p => p.BookID == id);
if (ModelState.IsValid)
{
_book.BookName = book.BookName;
_book.ISBN = book.ISBN;
context.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
public ActionResult Delete(int id)
{
Book book = context.Books.Single(p => p.BookID == id);
if (book == null)
{
return HttpNotFound();
}
return View(book);
}
[HttpPost]
public ActionResult Delete(int id, Book book)
{
Book _book = context.Books.Single(p => p.BookID == id);
context.Books.Remove(_book);
context.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
context.Dispose();
base.Dispose(disposing);
}
}
</book>
In this model we are using the Context class to perform the CRUD operations on the Book
entity. (To know how to use DbContext
class to perform CRUD operations refer:
An Introduction to Entity Framework for Absolute Beginners[^])
Adding the Views
Let us generate the strongly types scaffold views for this controller using the ASP.NET MVC view generations wizard. (To learn mode about default scaffold controller and views in ASP.NET MVC
refer: An Absolute Beginner's Tutorial on ASP.NET MVC for Web Forms Developers[^])
List of Books
Details of selected Book
Create a new Book Entry
Edit a Book entry
Delete a Book
Lets run and test the application
With this we have an application ready with the CRUD operation on a Books entity using the Entity framework code first approach. Let try to run this application. On first run
it will now show any data but it will create a new database at the location specified in the connectionString
.
Create a new Book Entry
Details of selected Book
Edit a Book entry
Delete a Book
List of Books
Managing enitity relationships - Adding Book Reviews
Let us modify the Book
details view to show all the reviews associated with the book too.
And now we will create a controller for reviews to add the reviews to a book. For now let us only implement the Create
method in this controller.
public class ReviewsController : Controller
{
BooksDbContext context = new BooksDbContext();
public ActionResult Create(int id)
{
Book book = context.Books.SingleOrDefault(b => b.BookID == id);
ViewBag.bookName = book.BookName;
Review review = new Review();
review.BookID = id;
return View(review);
}
[HttpPost]
public ActionResult Create(Review review)
{
try
{
if (ModelState.IsValid)
{
Book book = context.Books.SingleOrDefault(b => b.BookID == review.BookID);
book.Reviews.Add(review);
context.SaveChanges();
return RedirectToAction("Details", "Books", new { id = book.BookID });
}
return View();
}
catch
{
return View();
}
}
}
We will now add a simple view to add reviews to the books.
And once added these reviews will be available to on the books details page.
Now we have a simple application containing two entities with 1 to many relationship persisting the data in a database using the Entity framework code first approach.
Note: Before building the sample project, open the nuget
package manager and restore the missing packages.
Point of interest
This article was written for the absolute beginner's who have no idea about the code first approach. This article presents the reader with some introductory notes on what is code first approach and
how we can implement a simple ASP.NET MVC application with code first approach. What we have not talked about in this article but is still very important for this topic is the updation of database schema
whenever we are changing the models i.e. database migrations.
Note: We have not used any patterns like repository and unit of work in this article since the main idea of the article was to introduce the reader to the code first approach of
entity framework. Most experiences programmer will find this article very basic and not much helpful. But I hope this has been informative to all the absolute beginner's to Entity framework code first.
History
- 18 November 2013: First version