RepletoryLib.Data.Migrations
1.0.0
dotnet add package RepletoryLib.Data.Migrations --version 1.0.0
NuGet\Install-Package RepletoryLib.Data.Migrations -Version 1.0.0
<PackageReference Include="RepletoryLib.Data.Migrations" Version="1.0.0" />
<PackageVersion Include="RepletoryLib.Data.Migrations" Version="1.0.0" />
<PackageReference Include="RepletoryLib.Data.Migrations" />
paket add RepletoryLib.Data.Migrations --version 1.0.0
#r "nuget: RepletoryLib.Data.Migrations, 1.0.0"
#:package RepletoryLib.Data.Migrations@1.0.0
#addin nuget:?package=RepletoryLib.Data.Migrations&version=1.0.0
#tool nuget:?package=RepletoryLib.Data.Migrations&version=1.0.0
RepletoryLib.Data.Migrations
EF Core migration runner and data seeding for automated database setup on application startup.
Part of the RepletoryLib ecosystem -- standalone, reusable .NET 10 libraries with zero business logic.
Overview
RepletoryLib.Data.Migrations automates database schema management and seed data provisioning for EF Core applications. It runs pending migrations on application startup, executes data seeders in a defined order, and provides visibility into applied and pending migrations.
The migration runner includes retry logic for transient database failures and can be configured to run or skip migrations at startup.
Key Features
- Automatic migration on startup -- Apply pending EF Core migrations when the application starts
- Data seeding --
IDataSeederinterface with ordered execution for idempotent seed data - Hosted service --
MigrationHostedServiceintegrates seamlessly with ASP.NET Core hosting - Migration visibility -- Query applied and pending migrations programmatically
- Retry logic -- Built-in retry for transient database failures during migration
- Configurable -- Enable/disable migration and seeding via configuration
Installation
dotnet add package RepletoryLib.Data.Migrations
Or add to your .csproj:
<PackageReference Include="RepletoryLib.Data.Migrations" Version="1.0.0" />
Note: RepletoryLib packages are published to a local BaGet feed. See the main repository README for feed configuration.
Dependencies
| Package | Type |
|---|---|
RepletoryLib.Common |
RepletoryLib |
Microsoft.EntityFrameworkCore.Relational |
NuGet (10.0.0) |
Microsoft.Extensions.Hosting.Abstractions |
NuGet (10.0.0) |
Quick Start
using RepletoryLib.Data.Migrations;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddRepletoryMigrations<AppDbContext>(builder.Configuration);
{
"RepletoryMigrations": {
"RunOnStartup": true,
"SeedAfterMigration": true,
"TimeoutSeconds": 120
}
}
When the application starts, MigrationHostedService will automatically apply pending migrations and run registered seeders.
Configuration
MigrationOptions
| Property | Type | Default | Description |
|---|---|---|---|
RunOnStartup |
bool |
true |
Apply pending migrations when the app starts |
SeedAfterMigration |
bool |
true |
Run data seeders after migrations complete |
TimeoutSeconds |
int |
120 |
Migration command timeout in seconds |
Section name: "RepletoryMigrations"
Usage Examples
Creating a Data Seeder
Implement IDataSeeder to provision seed data. The Order property controls execution order (lower runs first).
using RepletoryLib.Data.Migrations.Interfaces;
public class RoleSeeder : IDataSeeder
{
public int Order => 1; // Runs first
public async Task SeedAsync(IServiceProvider serviceProvider, CancellationToken ct = default)
{
var context = serviceProvider.GetRequiredService<AppDbContext>();
if (await context.Roles.AnyAsync(ct))
return; // Already seeded -- idempotent
context.Roles.AddRange(
new Role { Name = "Admin", Description = "Full access" },
new Role { Name = "User", Description = "Standard user" },
new Role { Name = "ReadOnly", Description = "View only" }
);
await context.SaveChangesAsync(ct);
}
}
public class DefaultAdminSeeder : IDataSeeder
{
public int Order => 2; // Runs after RoleSeeder
public async Task SeedAsync(IServiceProvider serviceProvider, CancellationToken ct = default)
{
var context = serviceProvider.GetRequiredService<AppDbContext>();
if (await context.Users.AnyAsync(u => u.Email == "admin@example.com", ct))
return;
var adminRole = await context.Roles.FirstAsync(r => r.Name == "Admin", ct);
context.Users.Add(new User
{
Email = "admin@example.com",
FullName = "System Administrator",
RoleId = adminRole.Id
});
await context.SaveChangesAsync(ct);
}
}
Registering Seeders
builder.Services.AddRepletoryMigrations<AppDbContext>(builder.Configuration);
// Register seeders (they'll be discovered and executed in Order)
builder.Services.AddTransient<IDataSeeder, RoleSeeder>();
builder.Services.AddTransient<IDataSeeder, DefaultAdminSeeder>();
Querying Migration Status
using RepletoryLib.Data.Migrations.Interfaces;
public class DatabaseStatusController : ControllerBase
{
private readonly IMigrationRunner _runner;
public DatabaseStatusController(IMigrationRunner runner) => _runner = runner;
[HttpGet("db/status")]
public async Task<IActionResult> GetStatus()
{
var applied = await _runner.GetAppliedMigrationsAsync();
var pending = await _runner.GetPendingMigrationsAsync();
return Ok(new
{
AppliedMigrations = applied,
PendingMigrations = pending,
IsUpToDate = pending.Count == 0
});
}
}
Running Migrations Manually
If you disable RunOnStartup, you can trigger migrations manually:
builder.Services.AddRepletoryMigrations<AppDbContext>(builder.Configuration);
var app = builder.Build();
// Manually run migrations (e.g., from a CLI command or admin endpoint)
using var scope = app.Services.CreateScope();
var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
await runner.MigrateAsync();
API Reference
IMigrationRunner
| Method | Returns | Description |
|---|---|---|
MigrateAsync(ct) |
-- | Apply all pending migrations with retry logic |
GetAppliedMigrationsAsync(ct) |
IReadOnlyList<string> |
List of already-applied migration names |
GetPendingMigrationsAsync(ct) |
IReadOnlyList<string> |
List of migrations waiting to be applied |
IDataSeeder
| Member | Type | Description |
|---|---|---|
Order |
int |
Execution priority (lower = earlier) |
SeedAsync(serviceProvider, ct) |
Task |
Seed data idempotently |
Integration with Other RepletoryLib Packages
| Package | Relationship |
|---|---|
RepletoryLib.Common |
Direct dependency |
RepletoryLib.Data.EntityFramework |
Shares DbContext; use migrations for schema, EF for runtime access |
RepletoryLib.HealthChecks |
Check migration status as a health indicator |
RepletoryLib.Logging |
Migration progress logged via Serilog |
Testing
Test seeders in isolation using InMemoryDbContextFactory:
[Fact]
public async Task RoleSeeder_creates_default_roles()
{
var factory = new InMemoryDbContextFactory<AppDbContext>();
var context = factory.Create();
var services = new ServiceCollection()
.AddSingleton(context)
.BuildServiceProvider();
var seeder = new RoleSeeder();
await seeder.SeedAsync(services);
context.Roles.Should().HaveCount(3);
}
[Fact]
public async Task RoleSeeder_is_idempotent()
{
var factory = new InMemoryDbContextFactory<AppDbContext>();
var context = factory.Create();
var services = new ServiceCollection()
.AddSingleton(context)
.BuildServiceProvider();
var seeder = new RoleSeeder();
await seeder.SeedAsync(services);
await seeder.SeedAsync(services); // Run twice
context.Roles.Should().HaveCount(3); // Still 3
}
Troubleshooting
| Issue | Solution |
|---|---|
| Migrations fail on startup | Check database connectivity and credentials. The runner retries transient failures, but permanent errors will throw. |
| Seeders run in wrong order | Verify the Order property values. Lower values run first. |
| Seeders insert duplicates | Ensure seeders check for existing data before inserting (idempotent pattern) |
| Timeout during migration | Increase TimeoutSeconds in MigrationOptions for large schema changes |
License
This project is licensed under the MIT License.
Copyright (c) 2024-2026 Repletory.
For complete documentation, infrastructure setup, and configuration reference, see the RepletoryLib main repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
- RepletoryLib.Common (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 149 | 3/2/2026 |