Database creation on startup

Using dependency injection to create an EF database on startup

Home DailyDrop

Daily Knowledge Drop

When configuring an Entity Framework DbContext with the dependency injection container, it is possible to make use of the container to create an instance of the context on startup, to either create the database or apply database migrations.


Configuration

The AddDbContext extension method is used to configure the Entity Framework DbContext on startup, registering the context with the dependency injection container:

var builder = WebApplication.CreateBuilder(args);

// configure the context and add to the DI Container
builder.Services.AddDbContext<DemoContext>(options =>
    options.UseSqlServer(@"Server=.\SQLEXPRESS;Database=EFStartup;
        Integrated Security=True;TrustServerCertificate=True"));

var app = builder.Build();

app.MapGet("/blogs", (DemoContext context) =>
{
    return context.Blogs.ToList();
});

app.Run();

When the /blogs endpoint is called and a DemoContext is instantiated, the above will work provided that the database and relevent tables have already been created - if not, and exception will be thrown, as the database is not automatically created.

Next we'll have a look at how to ensure the database is created on startup, using the services registered with the dependency injection container.


Startup

The process of ensuring the database is created, is relatively straightforward - Entity Framework does most of the heavy lifting for us:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<DemoContext>(options =>
    options.UseSqlServer(@"Server=.\SQLEXPRESS;Database=EFStartup;
        Integrated Security=True;TrustServerCertificate=True"));

var app = builder.Build();

// this block ensures the database is created
#if DEBUG
using (var scope = app.Services.CreateScope())
{
    var startupContext = scope.ServiceProvider
        .GetRequiredService<DemoContext>();
    startupContext.Database.EnsureCreated();
}
#endif

app.MapGet("/blogs", (DemoContext context) =>
{
    return context.Blogs.ToList();
});

app.Run();

Some notes on the above code:

  • the #if conditional is used to ensure the code is only executed when debugging. It is NOT recommended to automatically create the database or apply migrations in non-development environments. The recommended approach is to use a CI/CD pipeline.
  • a new dependency injection scope is created (as the application host is technically not running yet) and a DbContext instance instantiated
  • the EnsureCreated method is called to create the database with the configured schema. This bypasses migrations - if the migrations are required to be run, then startupContext.Database.Migrate() should be called instead of startupContext.Database.EnsureCreated()
  • the EnsureCreated is designed to be used when doing testing or prototyping where the database is dropped and recreated with each execution

Notes

A useful and time-saving way to use the already configured dependency injection container to instantiate the database context, and have EF do the heavy lifting to create the database with the correct schema.


References

Dependency Injection of an Entity Framework Context within Program.cs Using Top Level Statements

Daily Drop 230: 09-01-2023

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net ef entityframework startup