Introduction to EntityFramework 6 Part 1: the basics of code-first

Introduction

EntityFramework is probably the #1 ORM choice in a database-driven .NET application. EntityFramework 6 comes with a couple of new exciting features that are worth checking out for all MVC 5 developers.

There are 3 approaches to working with EF in your project:

  • Database-first: you can point EF to a database and it will create a model for you using T4 templates. You can fine-tune the model in a design surface
  • Model-first: you have no database and use a design surface to draw your model. You can instruct the designer to create the database for you with all the tables
  • Code-first: write your model in code as classes and instruct EF to generate the necessary database and tables

In the series we’ll look at the code-first approach among other features of EF6.

Demo

I’ll use Visual Studio 2013 Express for Web to build the demo. Select New Project and then insert a new Blank Solution:

Insert new blank solution in Visual Studio

Call the solution Cars and press OK. The blank solution will be created in Visual Studio. Right-click the solution in the Solution Explorer, choose Add… New Project…, select the ASP.NET Web Application template. Call it Cars.Web. In the New ASP.NET Project window select MVC and click OK. The template will automatically include the EntityFramework-related libraries for you. You can see them if you expand the References section of the web project.

In a layered application design it’s customary to put the domain layer in a separate project. Right-click the solution and add a new Class library and call it Cars.Domain. Delete Class1. Add a reference to the Domain project from the Web project. Let’s add our first domain object. Add a new class to the Domain layer called Car. We’ll need to add MVC-related attributes to the class so add the following reference to Cars.Domain:

Add data annotations library to Domain layer

The Car object will look like the following:

public class Car
{
	public int Id { get; set; }
	[Required]
	[StringLength(50)]
	public string Make { get; set; }

	public CarCategory Category { get; set; }
}

…where CarCategory is an enum:

public enum CarCategory
{
	Family
	, Sports
	, Van
	, Estate
}

Is this POCO?

Let’s just stop for a second and ask ourselves this question. Is this Car class a true POCO, i.e. a true domain object as it’s used in the sense of Domain Driven Design? Probably not. We’re letting MVC related attributes enter our classes to add validation which destroys the plain and independent nature of the Car domain. Proper domain objects should be void of technology-related traits. If you’re not sure what I mean then you can skim through the DDD series referenced above. These annotations should be placed in view-models in the Web project so that client-side validation can take place first. However, this solution will be OK for this demo. The point is not to bloat the project and get bogged down by issues not related to EntityFramework.

We’ll commit a lot of these “sins” throughout the demo. You’ll see examples of SOLID being totally disrespected. We’ll concentrate on the technology but it’s up to you to organise your code as you see fit.

Data context

Let’s create our database context from scratch. As the Web layer already references the EntityFramework libraries we can keep it there. Again, this is a big no-no in a real life “serious” application, but it’ll do for now. Add a new folder called Database to the Web project. This folder will contain our database-related objects including the DB representation of our Car domain. You can keep your domain objects clean and store the DB representations separate. Add the following EF context class:

public class CarsDbContext : DbContext
{
}

…where DbContext lies in the System.Data.Entity library.

A collection of entities in the context is represented by the DbSet object. Add the following property to the context class:

public DbSet<Car> Cars { get; set; }

A DbSet is almost always mapped to a table in the database. So when you have an instance of a CarsDbContext object you can use to get hold of all Car objects in the data store and query the data with LINQ.

When you start a new MVC 5 project the template will actually provide you with a DbContext. Check the IdentityModels.cs file in the Models folder:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }
}

We discussed the purpose of the ApplicationDbContext in the series on Identity in MVC5 here. It derives from IdentityDbContext which in turn derives from DbContext. It is set up to work with User related data with EntityFramework: create new users, update users, add claims, store external OAuth metadata, store roles, logins etc. It’s meant to give you an EF implementation of every aspect around user management which is often considered a real pain by many programmers who want to concentrate on the real business domain instead. Make sure you at least skim through the series on Identity to learn more about this particular data context.

A little contemplation

We should pause for a minute and ponder what to do now.

We have two different contexts: the Cars context and the ApplicationDbContext. It is certainly possible to build on the ApplicationDbContext class and put all DbSet objects in there. On the other hand it seems like a good choice to keep the annoying user-related logic separate from the “real” business objects in the database.

Also, you may wonder how the ApplicationUser object could be ported to the Domain layer. After all, it is also an object that should reside in the Domain layer, right? The challenge here is that ApplicationUser derives from IdentityUser which lies in the Microsoft.AspNet.Identity.EntityFramework namespace. This means that if you want to keep the EF implementation of user management in the Domain layer then you’ll need to import the EF libraries into the Domain layer as well. That’s a serious step towards “contaminating” your business layer which should be clear of technological concerns. Like it happens in many projects, we are sort of trapped by technological issues: we want to keep our Domain layer clean but we may want to keep the EF user management provided by the MVC 5 template out-of-the-box because it’s convenient. If we want to provide our own User logic in the Domain layer then we’ll need to provide our own implementation of IUserStore, IUserLoginStore, IUserPasswordStore etc. which we saw in the series on Identity. This can be a long and tedious process which will take a long time to complete, time that could be spent on more business-related features. However, in that case we’re guaranteed to freely customise and optimise all aspects of our user-related logic.

If we decide to go with the EF implementation of user management then we have to accept the fact that we’ll use SQL Server as the user store mechanism and EF as the ORM framework of choice. This is again an example where we let technology take over some part of the domain.

On the other hand we can argue that user-related logic is not part of our code business domain. It’s only a necessary evil in order to let people log on and off, drive authentication and authorisation, create users etc. It’s possible that user management will not be part of the core domain of a typical business web application. That most likely belongs to some internal admin site. In that case you can leave the user management to EF as it is and concentrate on the core domain in the separate Domain layer. You can still choose a different data store to keep your domain objects in and have an SQL Server instance just for user-related data. We can even say that this is a good separation of concerns as the user management database might be used by other applications in a single sign-on scenario.

This all really depends on the philosophy you follow in your project. Whichever path you take you’ll have good arguments to back it up if anyone asks.

What do we do now?

We’ll certainly not go down the difficult and time-consuming path of providing our own implementation of user management in this demo. Also, user management is not part of our core domain. However, we still want to organise our code so that the user data context is located in the same place as the cars DB context. Add the following class called UserManagementDbContext to the Database folder:

public class UserManagementDbContext : IdentityDbContext<ApplicationUser>
{
	public UserManagementDbContext()
		: base("DefaultConnection")
	{

	}
}

Import the necessary libraries: Microsoft.AspNet.Identity.EntityFramework and Cars.Web.Models. In IdentityModel.cs erase the ApplicationDbContext class:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }
    }

The compiler will complain that ApplicationDbContext is not found in AccountController.cs. Update the constructor as follows:

public AccountController()
	: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new UserManagementDbContext())))
{
}

UserManagementDbContext will use a connection string defined in web.config as “DefaultConnection”. We want to make sure that the Cars DB context uses the same connection. Insert the following constructor to CarsDbContext:

public CarsDbContext() : base("DefaultConnection")
{
}

We’ll continue in the next post by creating the Cars database.

View the posts related to data storage here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: