EF Core 6 new features and changes for .NET 6
Published: Sunday 12 December 2021
EF Core 6 is upon us, and unless you have been living under a rock, you would know that .NET 6 was launched last month, and there are a number of changes were implemented to Entity Framework Core as part of the update. And we are going to have a look at some of them.
First, we will have a look at migration bundles. The migration bundle is an executable that contains everything to run a migration. It can be used as part of continuous deployment (CD) where it can be integrated as a deployment step in a DevOps pipeline.
C# coding challenges
Afterwards, we have a look at Entity Framework's support for temporal tables in SQL Server. Temporal tables are used to keep a full history of changes in a table, and these can now be integrated with EF Core.
Finally, we will have a look at pre-convention model configuration and how to set that up in EF Core. Gone are the days where we have to specify properties for common data types.
Feature #1 - Migration bundles
Entity Framework's migrations have been a familiar feature for code-first integration. As new features get implemented into an application, it's possible that new entities and properties are added to support these. Therefore, the database schema needs to kept in sync with the application.
This is where migrations come in. EF Core's migrations feature allows us to update the database schema and keep it in sync with the application's data model.
Migrations are generated in a class, and they contain the database schemas to update. We then run a PowerShell script to execute the script. This will either apply or revert the changes to the SQL Server database.
With EF Core 6, we can now create these migration scripts as an executable. This executable can be run as part of a deployment step in the DevOps pipeline, and we are going to go through the steps to set this up.
The first step is to make sure that we have migrations set up. We are assuming that you already have set up migrations in EF Core before. If you haven't, head over to Microsoft's documentation that talks about migrations.
With our migrations set up, we now need to bundle them into an executable. In Visual Studio 2022, we can go to Tools > NuGet Package Manager > Package Manager Console, and run the following script:
Bundle-Migration
An unexpected error
However, when we ran this script, we are greeted with the following error:
Build failed. Use --verbose to see errors.
So we ran it with the -verbose
parameter to see if that helped us.
Bundle-Migration -verbose
We had a slightly more descriptive error, but still not very helpful.
The process cannot access the file 'RoundTheCode.EFCore.dll' because it is being used by another process. [RoundTheCode.EFCore.csproj]
Afterwards, we tried to run it in Powershell (in admin mode) using the dotnet
command line:
dotnet ef migrations bundle --verbose
A resolution
Again, we were greeted with the same errors as above. The way we managed to get around it was to append the --configuration parameter to the dotnet
command line script, and ensured that it contained anything apart from debug
or release
.
dotnet ef migrations bundle --verbose --configuration abc
This worked for us, and generated a efbundles.exe
file. We can then run that file and it would update our database schema with the entities and properties within our application.
Please get in contact with us if you know why we are getting this error and how to resolve it.
Feature #2 - Temporal tables
Temporal tables were introduced in SQL Server 2016. These tables have the ability to keep a full history of changes within a table. This means that if we need to know what data was stored at any point in time, we can go ahead and query it.
EF Core 6 supports the ability for tables to be set up as temporal tables, and we are going to go through the steps to set it up.
In our DbContext
, we have set up a Player
and Team
entity, and we are now going to go ahead and make them temporal. We can do that by overriding the OnModelCreating
method and use the IsTemporal
method:
public class EfCoreDbContext : DbContext
{
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Player>()
.ToTable(action =>
{
action.IsTemporal();
});
modelBuilder.Entity<Team>()
.ToTable(action =>
{
action.IsTemporal();
});
}
}
Now that we've made that change, we need to add a migration for it. In Visual Studio 2022, we can go to Tools > NuGet Package Manager > Package Manager Console, and run the following script:
Add-Migration Temporal
Assuming we are not using migration bundles, we need to update the database and we can run the following script in Package Manager Console to do that:
Update-Database
Now that we've set up temporal tables, we can query the history of changes. We can do that by running a query similar to the following:
[ApiController]
public class TestController : ControllerBase
{
...
[HttpGet("sample")]
public virtual async Task<ActionResult<List<Team>>> GetSample()
{
var teams = await _dbContext.Teams.TemporalAll().Where(x => x.Id == 1).ToListAsync();
return Ok(teams);
}
}
The TemporalAll
operation retrieves the full history of changes for that particular table. If we wish to be date specific, we can use the TemporalAsOf
operation, passing in the UTC date as a parameter. There is also a TemporalBetween
, TemporalContainedIn
and TemporalFromTo
operation that we can use.
Feature #3 - Pre-convention model configuration
Regular users of EF Core will be familiar with having to set a max length for each string in an entity. Otherwise, each string would be migrated as a NVARCHAR(max)
column type in SQL Server. But with EF Core 6, we can set a convention for this so we don't have to set it for each individual property.
The way we do this is very simple. We can override the ConfigureConventions
method in our DbContext
and set our conventions within that.
The following is an example of setting all string properties to have a maximum length of 300 characters.
using RoundTheCode.EfCore.Entities;
namespace RoundTheCode.EfCore
{
public class EfCoreDbContext : DbContext
{
...
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
// Pre-convention model configuration goes here
configurationBuilder.Properties<string>().AreUnicode(true).HaveMaxLength(300);
}
...
}
}
Once we've set this up, we then need to add a migration for it. The migration will update all our string property to ensure that those columns have a maximum length of 300 characters.
Add-Migration Conventions
Afterwards, it's a case of updating the database, either through migration bundles or by running the Update-Database
command in Package Manager Console.
Of course, if we have explicitly defined a convention for a particular property in an entity, this will take precedence over anything in the ConfigureConventions
method.
See EF Core updates in action
Check out our video where we showcase these EF Core 6 updates in action:
In addition, if you can download the code example to try out these EF Core 6 updates for yourself.