WPF applications targeting .NET 5 or later often encounter issues when generating database migrasions with Entity Framework Core. The tooling fails to instantiate the DbContext because the design-time environment lacks the necessary startup configuration. Implementing the IDesignTimeDbContextFactory interface resolves this by providing an explicit creation path for the context.
Implementing the Design-Time Factory
Create a class that implements IDesignTimeDbContextFactory. This class must be located in the startup project or the project containing the context. The generic type parameter must match the specific context class being used.
public class DesignTimeContextFactory : IDesignTimeDbContextFactory<AppDatabaseContext>
{
public AppDatabaseContext CreateDbContext(string[] args)
{
var options = new DbContextOptionsBuilder<AppDatabaseContext>()
.UseSqlite("Filename=local_store.db")
.Options;
return new AppDatabaseContext(options);
}
}
Context Configuration
The database context should handle connection strings gracefully, prioritizing options passed via the constructor while providing a fallback for design-time operations. Seed data can be configured within OnModelCreating.
public class AppDatabaseContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<Role> Roles { get; set; }
public AppDatabaseContext(DbContextOptions<AppDatabaseContext> options)
: base(options) { }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite("Data Source=app_data.db");
}
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Role>().HasData(
new Role { Id = 101, Title = "Contributor", Description = "Standard access" },
new Role { Id = 102, Title = "Supervisor", Description = "Administrative access" }
);
modelBuilder.Entity<Account>().HasData(
new Account
{
Id = 1001,
Username = "demo_user",
Passcode = "secure_pwd",
RegisteredAt = DateTime.UtcNow,
RoleId = 101
},
new Account
{
Id = 1002,
Username = "system_admin",
Passcode = "admin_pwd",
RegisteredAt = DateTime.UtcNow,
RoleId = 102
}
);
}
}
Prerequisites
Ensure the following NuGet packages are installed in the project:
Microsoft.EntityFrameworkCoreMicrosoft.EntityFrameworkCore.SqliteMicrosoft.EntityFrameworkCore.Tools
The connection string defined in the factory or OnConfiguring must be valid and accessible during the design-time process. This approach applies similar to other providers like MySQL or PostgreSQL.
Executing Migrations
Migration commands are executed via the Package Manager Console or the .NET CLI. Ensure the correct project is selected as the startup project.
To create a new migration snapshot:
Add-Migration InitialCreate -Context AppDatabaseContext
To apply pending changes to the database:
Update-Database
If using the .NET CLI:
dotnet ef migrations add InitialCreate
dotnet ef database update