EF Core Pt. 1 - Basics
In a series of articles I will talk about Entity Framework Core. In this first article we discuss the basics of Entity Framework and basic setup. All articles will be using .Net 7 and EF Core 7.
As you probably already know, EF (Entity Framework) is an ORM (object-relation mapping) framework for ADO.NET. It is a set of technologies that support development of data-oriented applications. EF will map objects to and from database tables makes it easier to develop these applications. Some common complaints about EF has been it's bad performance, simplicity for developers to store data into databases without understanding of how relational databases should be structured for good performance.
The first version of EF was included in .Net Framework 3.5 SP1 in 2008. Since then several versions has arrived, fixing issues and making the framework more competent. Entity Framework 6.4 was the latest release on the .Net Framework, and is no longer developed.
In 2016 Microsoft released the first version of EF Core alongside ASP.NET Core 1 and .Net Core 1. This was a total rewrite of the framework supporting to run on Windows, Linux and OSX, and support to a range of relation and NoSQL data stores. Another big change was that Microsoft released it as open source on Github. In 2022 released the latest version EF Core 7.
In the beginning a separate visual tool in Visual Studio was commonly used to design the data model and database, or construct a model from an existing database. This tool was hard to work with due to bugs and hard to merge changes into when a team was doing changes. This method is named model-first. Even though the code-first model existed it was missing features and hard to work with.
In EF Core the model-first model is not supported any more, instead you need to use the code-first model. Still it is possible to create a code-first model from an existing database.
Use EF Core
In this article we will create a data model, setup EF Core and create a first version of the database. This database and model will be used in all articles following.
To start with we will be using an empty ASP.NET Core Web API using minimal API. The reason to use an ASP.NET based template is to get the Dependency Injection framework.
Some extra steps in the newly created project are needed.
First clean program.cs so it looks like this:
Second add the two following nuget packages:
The final step to make all clean is to modify the Properties/launchSettings.json to not open a browser and have unnecessary configuration. Only keep the https section as below:
The basic data model looks like this (only the tables with keys are presented)
The declaration of the data model (entities) are as follows:
When using the code-first model you are able to set attributes to set behavior on the entities properties. These data annotations (attributes) will be used by EF Core to construct the database. My opinion is that clutters the model and instead I will do it separately. One important thing to learn about EF Core is that it uses some common naming conventions and will automatically construct the database model by them. By learning and using these naming conventions you will be writing less code - and that is something we all want, right.
To use EF Core we need a database context object and that is done by create our own inherited from DbContext. During the first instantiation of the DbContext EF Core will run the OnModelCreating function and keep this in memory. In this function you are able to manually set up how the model should be reflected in the data store.
As you see above we don't need to define the primary keys and the foreign keys, except for the one-to-one relation between Customer and Address. We also declare the precision on the decimal datatype, to not get a warning, but the precision used is the same as the default EF Core will use.
Time to wire the DbContext into the dependency injection. Add the following in program.cs below the comment "// Inject all DI here..."
The connection string should of course come from example the appsettings.json file but can for demo purpose be declared above as follows:
If you are running SQL Server locally you need to turn of the encryption as it is done in the connectionstring example above (added a newline in there to have it wrapped).
All changes to the data model is done by migrations, and for that we let EF Core generate these for us. Each migration will contain the needed SQL to upgrade the database to the current state and also the SQL needed to downgrade to previous version.
A migration will contain one partial class file with the upgrade/downgrade functions and a partial class file that contains the upgraded final state in total. After a migration is created the database context modelsnapshot file is updated, to be the final state in total.
To create a migration use the DotNet CLI and add the EF-Core package
and from a command window located in the root directory path create an initial migration
In the project a migrations folder will be created with the migration files and the database context snapshot file.
Finally apply the migration from the CLI with this command:
When you create a migration the EF Core command will try to start the application to get the DbContext. In some cases, like if it starts some timer jobs, this is not a wanted behavior. To override this behavior you can create a factory class implementing IDesignTimeDbContextFactory that will be used instead that will return the instantiated DbContext.
An example of this factory looks like this:
EF Core will look if there exists this type of factory and use this one instead of bootstrapping the whole application.
We still have one small problem, the migration is not run automatically on startup of the application. Which means we need to run the migration manually before starting it up. This can be done in program.cs during the application startup, after we have built the app and before the app.Run().
We need to do it after the app is built to ensure all DI services are registered. To get the DbContext out from DI we create a new ServiceScope and requests the DbContext. When we have the context we run the migrations. EF Core will apply all migrations in date order (or sorted by filename) to ensure the data store model is up to date.
Thats all to get started with EF Core. In the next article I will discuss how to configure EF Core and what options you have.
Mikael Johannesson is a seasoned senior consultant with over 20 years of experience in the IT industry. He currently works at Precio Fishbone, where he is one of the software architects for our digital workplace solution Omnia and also provides expert consultation services to clients across various industries.Send email