Entity Framework Core Code-First - Generate Covering Index with Columns Included
In SQL Server or some other relational databases, it is a very common requirement to create covering index with columns included in index pages beside the index key columns. With Entity Framework Core, you can also easily generate covering indexes using purely C# code.
Scenario
For Kontext website, backend database storage is Azure SQL Database. Most recently, Azure portal recommends creating two indexes to improve query performances. The recommended indexes details look like the following screenshots:
Both recommendations are covering indexes.
Create indexes using T-SQL
Azure portal also allows us to directly apply these indexes to the database using T-SQL.
For example, the following statements are generated by Azure:
CREATE NONCLUSTERED INDEX [nci_wi_FlexContents_673086CD9DE40ABE97C36E561E7D87B6] ON [flex].[FlexContents] ([Blocked], [IsDeleted], [IsPublished], [Tag]) INCLUDE ([SiteID]) WITH (ONLINE = ON) CREATE NONCLUSTERED INDEX [nci_wi_FlexActions_6E4A2EE58FF9DE15144A33EDD89D277E] ON [flex].[FlexActions] ([IsDeleted], [SiteID], [ContentID]) INCLUDE ([DateCreated], [Type]) WITH (ONLINE = ON)
I can directly apply these indexes into database however since I'm using code-first approach, I will use Entity Framework APIs to implement this changes.
Entity Framework Core Code-First
Microsoft official documentation shows how to use code-first to create indexes with included columns.
Refer to the following page for more details:
Constraints
As included column is not implemented in all databases, thus this API (IncludeProperties) is not directly included Entity Framework core libraries and you need to included the related database extension packages into your project references.
For my case, I need to include SQL Server package:
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.5" />
If you use other databases, please change the package reference accordingly.
Implement this change
With the extensions methods added by the database specific package, I can now easily add this packages via the following code:
builder.Entity<FlexContent<TKey>>(entity => { // Performance improvement index entity.HasIndex(e => new { e.Blocked, e.IsDeleted, e.IsPublished, e.Tag }) .IncludeProperties(e => e.SiteID); }); builder.Entity<FlexAction<TKey>>(entity => { // Performance improvement index entity.HasIndex(e => new { e.IsDeleted, e.SiteID, e.ContentID }) .IncludeProperties(e => new { e.DateCreated, e.Type }); });
Generate migrations using CLI
After the models are updated, I can use entity framework CLI to generate migrations:
dotnet ef migrations add FlexContentActionPerformanceIndex
After this, the website project will have a few migrations classes generated automatically as the following screenshot shows:
Apply changes to database
We can run CLI command to apply the changes to databases in different environment:
dotnet ef database update
The command line generates the following output:
It executes the two statements to create indexes and then insert a migration record into __EFMigrationsHistory table in the database.
Summary
As shown in the above code snippets, it is very easy to use Entity Framework Core APIs to create indexes in the data model. With IncludeProperties API implemented some database specific packages, you can also create indexes with columns included.
If you prefer to give it a name for your indexes, you can use HasName API.