Using compiled models can reduce EF Core's startup time for applications that have large models, usually consisting of hundreds or thousands of entity types and relationships.
- Startup time refers to the time taken to execute the first operation on a
DbContext
when that particularDbContext
type is used for the first time in the application. - It is important to note that creating an instance of the
DbContext
alone does not cause the EF model to be initialized. - Instead, the model is initialized when a typical first operation such as
DbContext.Add
or executing the first query is performed.
Install Tools
Compiled models are created using the dotnet ef
command-line tool. You can install dotnet ef
as either a global or local tool, but most developers prefer installing dotnet ef
as a global tool using the following command:
dotnet tool install --global dotnet-ef
The following command will update the tool.
dotnet tool update --global dotnet-ef
Before you can use the tools on a specific project, you'll need to add the Microsoft.EntityFrameworkCore.Design
package to it.
dotnet add package Microsoft.EntityFrameworkCore.Design
Generate Compiled Model
To generate the compiled model, you can use a new dbcontext optimize
command:
dotnet ef dbcontext optimize
When the above command is executed successfully, you will see the following output.
C:\Users\Muhammad Waqas\Source\repos\EFCoreDemo\EFCoreDemo>dotnet ef dbcontext optimize
Build started...
Build succeeded.
Successfully generated a compiled model, to use it call 'options.UseModel(BookStoreContextModel.Instance)'. Run this command again when the model is modified.
You will also notice that a new folder CompiledModels is added in your Solution Explorer that contains several files. Let's open the context model file and you will see some auto-generated code as shown below.
// <auto-generated />
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
#pragma warning disable 219, 612, 618
#nullable enable
namespace EFCoreDemo.CompiledModels
{
[DbContext(typeof(BookStoreContext))]
public partial class BookStoreContextModel : RuntimeModel
{
static BookStoreContextModel()
{
var model = new BookStoreContextModel();
model.Initialize();
model.Customize();
_instance = model;
}
private static BookStoreContextModel _instance;
public static IModel Instance => _instance;
partial void Initialize();
partial void Customize();
}
}
This is a partial class with partial methods that can be implemented to customize the model as needed.
To use the compiled model, we need to configure the DbContext
as shown below.
public class BookStoreContext : DbContext
{
public DbSet<Author> Authors { get; set; }
public DbSet<Book> Books { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseModel(BookStoreContextModel.Instance)
.UseSqlServer(@"Data Source=(localdb)\ProjectsV13;Initial Catalog=BookStoreDb;");
}
}
Limitations
There are certain limitations associated with compiled models:
- Global query filters are not supported
- Lazy loading and change-tracking proxies are not supported
- Custom
IModelCacheKeyFactory
implementations are not supported, but multiple models can be compiled and loaded as needed - The model must be updated manually whenever there is a change in its definition or configuration.
Compiled models should only be used when EF Core startup time is excessively long. It is usually not worthwhile to compile small models. If any of these features are essential for your project, please vote for the relevant issues linked above.