Seeding
Seeding populates a repository with initial data during application startup. The lifecycle service handles data resolution and delegates insertion to the driver's lifecycle handler.
Seed Strategies
The SeedStrategy enum controls when seed data is applied:
| Value | Behavior |
|---|---|
Never | No seeding is performed. |
Always | Seeding is always performed. |
IfMissing | Seeding is performed only when the repository does not exist. |
ByEnvironment | The strategy is delegated to an IRepositoryLifecycleProfile. |
Environment-Aware Seeding
When SeedStrategy is ByEnvironment, the service:
- Reads
EnvironmentNamefrom options (or resolves it fromIHostEnvironment). - Queries the registered
IRepositoryLifecycleProfilefor the effective strategy. - Falls back to
Alwaysif no profile is registered.
Seed Data Sources
Seed data can come from three sources (evaluated in order):
- Explicit data passed to
SeedRepositoryAsync(data). - An
IRepositorySeedDataProvider<TEntity>registered in DI. - A
SeedActioncallback onRepositoryLifecycleOptions.
If no source provides data, seeding is silently skipped.
Automatic Discovery
When you call ConfigureLifecycle(), the builder automatically scans the entry assembly for any class implementing IRepositorySeedDataProvider<TEntity> and registers it with TryAdd — so explicit registrations always take priority.
public class ProductSeedProvider : IRepositorySeedDataProvider<Product> {
public IEnumerable<Product> GetSeedData() {
yield return new Product { Name = "Widget", Price = 9.99m };
}
}
builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>(...)
.ConfigureLifecycle(options => {
options.SeedStrategy = SeedStrategy.Always;
});
Explicit Registration
When you need to register providers from multiple assemblies or want to be explicit, use WithSeedDataFrom():
builder.Services.AddRepositoryContext()
.UseInMemory(b => b.WithLifecycle())
.ConfigureLifecycle(options => { ... })
.WithSeedDataFrom(typeof(ProductSeedProvider).Assembly,
typeof(OtherSeedProvider).Assembly);
Seeding Methods
Via WithSeedData (Recommended)
The RepositoryContextBuilder provides two overloads:
Using a provider class:
public class MyEntitySeedProvider : IRepositorySeedDataProvider<MyEntity> {
public IEnumerable<MyEntity> GetSeedData() {
yield return new MyEntity { Name = "Default Item", IsActive = true };
yield return new MyEntity { Name = "Another Item", IsActive = true };
}
IEnumerable<object> IRepositorySeedDataProvider.GetSeedData()
=> GetSeedData().Cast<object>();
}
builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>(...)
.ConfigureLifecycle(options => {
options.SeedStrategy = SeedStrategy.Always;
})
.WithSeedData<MyEntity, MyEntitySeedProvider>();
Using inline data (no provider class needed):
builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>(...)
.ConfigureLifecycle(options => {
options.SeedStrategy = SeedStrategy.Always;
})
.WithSeedData<MyEntity>(new[] {
new MyEntity { Name = "Default Item", IsActive = true },
new MyEntity { Name = "Another Item", IsActive = true }
});
All overloads register an IRepositorySeedDataProvider<TEntity> in DI behind the scenes. The service resolves it during SeedRepositoryAsync<TEntity> and the driver's lifecycle handler inserts the data.
Explicit
WithSeedDatacalls useAdd(always registers). Auto-discovered providers useTryAdd— so explicit wins if both are present.
Via SeedAction Callback
Override the default seeding behavior with a custom action:
builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>(...)
.ConfigureLifecycle(options => {
options.SeedStrategy = SeedStrategy.Always;
options.SeedAction = (sp, entityType, seedData) => {
if (entityType == typeof(MyEntity) && seedData is IEnumerable<MyEntity> entities) {
var context = sp.GetRequiredService<AppDbContext>();
context.Set<MyEntity>().AddRange(entities);
context.SaveChanges();
}
};
});
The SeedAction receives the service provider, the entity type being seeded, and the resolved seed data (or null).
Via Explicit Call
Trigger lifecycle operations explicitly from your application:
var lifecycleService = app.Services.GetRequiredService<IRepositoryLifecycleService>();
await lifecycleService.CreateRepositoryAsync<MyEntity>();
await lifecycleService.SeedRepositoryAsync<MyEntity>(new[] {
new MyEntity { Name = "Startup Item" }
});
When
SeedRepositoryAsyncis called with explicit data andSeedStrategyis notNever, the data is passed directly to the driver's lifecycle handler without consultingIRepositorySeedDataProviderorSeedAction.