Entity Framework Core 3.1 - Part 1

Entity Framework Core 3.1 - Part 1

Overview

What is this about?

This post is one of many in a series of posts on Entity Framework Core.

I have attempted to summarise what I learned while working with Entity Framework Core, from stackoverflow answers, to entity framework official docs to courses on pluralsight. In this journey, I found, the pluralsight course, Entity Framework Core: Getting Started by @julielerman most useful.

As someone who spent the past few years primarily on managing people, I missed out a lot on the tech side of things. So these days, I have been playing catchup. And guess what? There is a lot to catchup! But as with any learning, it isn't a sprint, it is a marathon and a pretty long one.

Reading this will give you a gist of the things that you must know when using EF Core.

If you are new to EntityFramework, you may not benefit much from this series of posts on Entity Framework as the foundation is not covered here.

What is EF Core?

EF Core is an Object Relational Mapper which came into the market in about 2008 and has been Microsoft's official data access technology for .NET development. It is widely used in production applications around the world. It is also cross platform (like .NET Core).

Object Relational Mapper

ORMs are designed to make it easy for developers to link how data is structured in your database with data in your application's classes. So if you didn't have an ORM, you'd have to manually write a lot of boiler plate like code to transform data that you retrieve from the database and to the database. ORMs also allow you to express SQL in application code as if they were methods on classes.

The ORM would abstract all the data access behind the scenes with some mapping layer that gives developers the flexibility to interact with the underlying database.

EF Core Providers

I have only ever used Entity framework to fetch data from SQL Server databases. But EF Core actually has packages that allow you to interact with several different databases. A full list of providers can be found in the documentation. It even has one to interact with an in memory database which is especially useful for automated testing apparently. I have never tried using this myself. Probably, something I'll try out and write about in another post.

It also currently supports a non-relational database CosmosDB. This is also something I have never personally used. So something to experiment with later and maybe share my experience here.

EF Core 3

According to Julie Lerman, EF Core 3.0, is a foundation for the future. Because this was a new foundation for the future, it does come with a lot of breaking changes though. So, it might be totally worth checking the list of breaking changes before you upgrade.

EF Core 3.1 is the Long Term Support version. More details can be found about .NET implementations supported by EF Core.

EF Core Nuget Packages

Unlike earlier version of Entity Framework, Microsoft has done a better job of organising and breaking down the nuget packages of EF Core. They are all neatly named as Microsoft.EntityFrameworkCore.*. To make it easier to get the right EF package, look for one with the intended data provider in the name. Example, if you wanted to interact with SQL Server database, you'll need Microsoft.EntityFramework.SqlServer package. That will install all the underlying dependencies automatically for you thanks to Nuget. You can do this using the package manager console or using the Package Manager UI.

From Console (go to the project directory where you need to install it and run): Install-Package Microsoft.EntityFramework.SqlServer And you can see it pulling down all the depencies for you!

Data Model

For a new project where you are introducing entity framework core, all you have to do is create a Class that encapsulate the DbContext that you want to access. This is easily done by inhertiting from the DbContext class. To read more about how Models can be created and configured, checkout the docs. A context represents a set of tables that you need access to to achieve or perform something for that part of the application.

Any configuration to the DbContext is done by overriding the OnConfiguring method on DbContext, which takes in a parameter of type DbContextOptionsBuilder. An example snippet configuring your context to use SqlServer with a hard-coded connection string is below. Please keep in mind that hard-coding connection strings are not recommended for production applications, just a way to show how to here.

1    public class MyTestContext: DbContext
2    {
3        public DbSet<MyTest> MyTests { get; set; }
4        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
5        {
6            optionsBuilder.UseSqlServer("Data Source-= (localdb)\\MSSQLLocalDB; Initial Catalog = MyTestDatabase");
7        }
8    }

This database may not exist yet. However, using some tools that you get with entity framework core, you can actually generate a database creation script(s) for you from the entity models you have defined. Just make sure you set the right connection string, so that you don't end up creating databases in the wrong server.

Database Creation and Updates with Migrations

Migrations are the API that you would use to create or update schema or data of a database. Any change you do to the model can be used to create a new migration file and you can use that file to apply migrations to the database!
In order to run migrations, there are different nuget packages that you might need to install.
To run migrations commands, you need to install the following packages, depending on the platform:

  • Powershell: Microsoft.EntityFrameworkCore.Tools
  • dotnet CLI: Microsoft.EntityFrameworkCore.Tools.Dotnet
powershell vs dotnet-cli uses different names

To create database Migrations:

  • Microsoft.EntityFrameworkCore.Design (dependency of Tools package)

If you are using Visual Studio for your development workflow, then it would be easier to stick to Powershell package and use the Nuget Package Manager Console to execute your ef-migrations related commands.

  • Try running: get-help entityframework
screenshot of get-help entityframework command in Nuget package manager console in Visual Studio 2019

Creating a migration

When creating a migration within visual studio's Nuget package manager console, feel free to run: Add-Migration.

The only thing worth noting, is that you have to execute this command in a project that has a runtime.

The Add-Migration command generates a new Migrations folder and generates some files in it.

Everytime this command is run, entity framework generates the resulting migration file and also creates/updates a YourContextModelSnapshot.cs. This second file is crucial as it is where EF Migrations keeps track of the current model. This is used by the Add-Migration file to check against the previous model and incrementally make changes in the new migration file.

Updating the database

EFCore's script-migration command generates the relevant SQL to run against the corresponding database, especially useful for production execution. This is particularly useful if you want to hand over the script to another team or a database administrator to execute in production. The changes must be examined and can even be tweaked for production use.
For non-production databases, you can run the migration against a particular database instance based on the connection string you have configured in your project settings using update-database command.

different commands to make database changes for Powershell vs dotnet cli

Create models from an existing database

This is handy when you want to work on an application trying to interact with an existing database. scaffold-dbcontext command is your friend here. It accepts several different parameters. However, as a bare minimum, all you need to provide it is the connection string and the provider.

1scaffold-dbcontext -provider Microsoft.EntityFrameworkCore.SqlServer -connection "Data Source = (localdb)\MSSQLLocalDB; Initial Catalog = MyTestDatabase

Remember to run this in the project where you want the models to be created. You then magically get the entities are created for you! The names of the classes will default to match the tables. Keep that in mind and check if the names meet your conventions and tweak accordingly. Read more about this in the docs.

The default conventions followed by EF Core to determine mappings to the DB may not be your choice. However, you can override this as I mentioned earlier in your DbContext file using the fluent API in the OnModelCreating(ModelBuilder modelBuilder).

Another way to overriding conventions is using DataAnnotations. Although this method is pretty restrictive and limited in terms of the flexibility to override behaviour, it, nonetheless, provides a good alternative for overriding just a few entities, or say, property names.

Cardinality and Relationships in EntityFramework Core

In a relational database it is pretty common to have many to many relationships.

The reason, I am stating this relationship specifically here because, the implementation of this sort of a relationship doesn't come out of the box in Entity Framework Core, like it used to in Entity Framework 6. This might seem like a step back, but it is only a matter of time that this will be implemented.

Let us go through this using a classic example below, with the solution.

 1    public class Student
 2    {
 3        public int Id { get; set; }
 4        public string Name { get; set; }
 5    }
 6    
 7    public class Course
 8    {
 9        public int Id { get; set; }
10        public string CourseName { get; set; }
11    }

In order to connect a Student to multiple courses and a course with multiple students in Entity Framework Core, you need to define a mapping class explicitly called a joining entity and then reference this joining entity in the corresponding entities where you would like the convenience of navigation.

1    public class StudentCourse
2    {
3        public int StudentId { get; set; }
4        public Student Student { get; set; }
5    
6        public int CourseId { get; set; }
7        public Course Course { get; set; }
8    }

Now that you have the joining entity called StudentCourse defined, you can then refer to this or a list of these in the Student and Course classes as properties to enable easy navigation from Student to Courses and vice-versa. So your Student and Course classes would look like this:

 1    public class Student
 2    {
 3        public int Id { get; set; }
 4        public string Name { get; set; }
 5        public IList<StudentCourse> StudentCourses { get; set; }
 6    }
 7    
 8    public class Course
 9    {
10        public int Id { get; set; }
11        public string CourseName { get; set; }
12        public IList<StudentCourse> StudentCourses { get; set; }
13    }

Now that's great, but how do you tell entity framework core that StudentCourse record must connect the two? Provide this configuration information in the DbContext implementation by overriding the good old OnModelCreating method. This is absolutely necessary so that EntityFramework can actually map the two entities.

1    public class UniversityContext : DbContext
2    {
3        protected override void OnModelCreating(ModelBuilder modelBuilder)
4        {
5            modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.StudentId, sc.CourseId });
6        }
7    }

You just told entity framework how the StudentCourse record connects Students and Courses.

Updating changes from new migrations

1add-migration <migration_name>

Read more about this in the docs.

As this post is a pretty long read, although broken down into small sections, I will cover more on working with related Data and other database objects like views and stored procedures in the next post

Useful Resources

comments powered by Disqus