Entity Framework Core

The app that does not need persistence is the exception to the rule.  Most commonly, persistence comes in the form of a database, such as Microsoft SQL Server.  But communicating with the database can be problematic.  First off, databases do not store data the way that humans think about it.  The structure of a database table and the logical structure that it represents can be two completely different ideas.  And expressing those ideas involves two different languages.  For relational databases, this means SQL, the Structured Query Language.  SQL is not the most user friendly language in the world and it is meant to describe data the way a database thinks about it.  As software engineers, we humans think about real world representations of data.  We use languages such as C# in order to express our thoughts.  So there is a gap in the middle.  And Entity Framework Core fills that gap.

Entity Framework Core, or EF Core, is an Object Relational Mapper or ORM.  It maps between objects (written in C# for us) and relational database tables (expressed in SQL).  It’s the glue between them.  Using EF Core, the amount of SQL the application developer has to write can be greatly reduced.  You can’t completely isolate yourself from knowledge of databases, but you can abstract away much of the detail and focus on the logic of your application instead.

One of the awesome things about EF Core is how easy it is to set up.  Just by creating and ASP.NET Core application with the .NET Core SDK version 2.0, EF Core is already included in the Microsoft.AspNetCore.All NuGet metapackage.  In addition, a number of commands extend the dotnet CLI tool when the EF Core tooling is added to an ASP.NET Core project.  Also, switching between development and production databases is as simple as changing the connection string for some applications.  So in this post I’ll be using SQLite as a development database but I could very easily migrate this project to SQL Server on Azure or a self-managed server.

To get started, I’ll create an empty ASP.NET Core application and add the most rudimentary of MVC support to it.  I won’t go over the details here.  If you need to review that refer the to my post on getting stared with ASP.NET Core MVC here(link soon).  I’ll name the project CoreStore for a simple e-commerce site.

Now I’m going to add a model class to the project.  I’ll do this in a new folder called Models.  The model class will be Product and it will live in Product.cs.  It’s a simple class with just a few properties:

So I’ve defined a model class before creating a database.  This is what is known as the code-first method.  The structure of the database will be interpreted from the model classes.  There is also the database-first method which derives object classes from an existing database.

Next I need a way to get the Product model into a database table.  This is the job of a context.  An EF Core context class will derive, eventually, from the base DbContext class in the EF Core assemblies.  I’ll create one called StoreContext in the Models folder:

The context class constructor requires a parameter of DbContextOptions which is generic on the type of the context class which is StoreContext in this case.  That DbContextOptions parameter is then passed to the constructor of the parent class.  I’ll add a property of type DbSet that will represents the rows in a table which EF Core will map to my Product model class.  DbSet needs a generic parameter on the type of the model class.

This next step is optional, but good to know about.  By overriding the OnModelCreating method in the context class, we can provide fine grained configuration for the database.  Here I’ll do something simple like specify a name for the table in the database.  By default, EF Core will use the name of the DbSet, Products in this case.  But I want it to be just Product.

The context class is almost ready.  The last step is to register it with the application in the Startup class.  Add this code to the ConfigureServices method:

You’ll need to add a few namespaces to the file like CoreStore.Models and Microsoft.EntityFrameworkCore but that can be done easily with Visual Studio Code. (Click here(link soon) to learn more about writing .NET Core apps with Visual Studio Code.)  The big takeaway here is the lambda expression which tells EF Core that the application will be using the SQLite database and that the path to the database file will be store.db in the root of the project.

At this point I need some sample data in the database.  A number of ways can accomplish this but I’m going to use a pattern that I’ve seen a lot in simple applications like this one which is to create a static initializer class.  I’ll create a new file, DbSetup.cs in the Models folder:

The Setup method takes a StoreContext and uses the Products DbSet to add several Product objects.  The the changes are saved to the context which persists them to the database.  However, I don’t want to add these Product objects more than once.  Using the LINQ Any method on the DbSet I can check to see if there are existing Product objects.  If there are not, I know the database has just been generated by the call to EnsureCreated in the first line of the method.  The only thing left to do now is to call this method from the Startup class in Configure.  Place this at the bottom of the method:

The context parameter is not defined.  So how do we create it?  It turns out that registering a context with AddDbContext in ConfigureServices also registers it with the dependency injection container.  So I can specify a parameter of StoreContext in Configure and the dependency injection container will handle it for me.  This is called seeding the database.  This is only one method.  In production you would likely use migrations but this will do for now.

In Visual Studio Code, press F5 to run the project.  The result in the browser won’t be that impressive because the only view is the Index which is what you’ll see.  However, take a look at the Explorer window in Visual Studio Code.  Notice the store.db file has been created.  Also, in the debug console, scroll up and see that EF Core has executed a bunch a SQL statements.  There is one to create a table called Product with a primary key of ProductID.  And there are a couple to insert each of the products in the DbSetup class.  You can also view the contents of the database file with the SQLite command line tool or a GUI interface like DB Browser for SQLite.  Both are free, open source, and cross-platform.  Here is the result of opening the Product table in DB Browser for SQLite on macOS.

Notice also that a convention is being followed.  I intentionally named the identifier of the Product class as ProductID.  EF Core will recognize this pattern and designate the primary key.  I could also just use ID, without the class name.  And notice that the table was named like the context class was told.

Now to get this data into a view.  I’ll first create a new controller, called ProductController.  For now, it will have a single action method Index that will get all of the Product object from the context and pass them to the default view.

The context for the ProductController is initialized with a parameter passed to the constructor using the dependency injection container.  Also, note the use of the LINQ ToList method.  This will generate a result that the view can use.  I’ll create the Index.cshtml view next in the Views/Product folder.

This is pretty straightforward Razor code just iterating over the IEnumerable model to display the Product object data in a table.

For ease of navigation, before running this, I’m going to add a _Layout.cshtml file to the Shared folder and a _ViewStart.cshtml file to set the Layout.

The last exercise in this post will let users ‘purchase’ a quantity of an item, or at least tell them how much the total is.  First I’ll create a new Order action and view for the Product controller:

The action takes the id parameter which will be passed by the route.  Remember that the application uses a default route with an optional id in the last part.  Then it uses that ID to find the product in the context, with several LINQ methods.  It’s possible that the id is not found.  If so, show the NotFound view.  Otherwise show the product in the default view.  The view file will show a form to allow the user to give a quantity.  So we’ll have to add another action to handle the POST form data.  But first, the default view:

This is basic Razor code.  Notice that I am passing the ProductID back to the POST in a hidden field.  This will make sense later on.  To get to this view I have to add a link to the Index view:

To process the form data, I’ll create a helper object.  For simplicity I’ll put it in the Models folder even though it is more like a Data Transfer Object (DTO).  See the next post for more info on DTOs.

This just mirrors the names of the form fields.  However, I’ll use it to cleanly pass the data values to the POST action method for the Order.

This code just looks up the Product in the context.  I used First instead of FirstAndDefault because technically all product ids coming from the form should be valid as a nonexistent one would have been prevented in the GET method.  Then I multiply the price by the quantity and return the value to the Receipt.

This will let the user see the total.  That’s all I’ll cover in this post because it’s getting long.  In a future post I’ll cover relationships and then later migrations.

The code for this post can be found on Github.

Leave a Reply