Seed Data Generator

Generates a DatabaseSeeder class that inserts initial rows into your database tables at application startup.

Table of contents
  1. What It Generates
  2. Configuration
    1. Rules
  3. Generated Output
  4. Integration with DI and Startup
  5. Multiple Entities
  6. Next Steps

What It Generates

The seed data generator produces a single DatabaseSeeder.cs file containing INSERT statements for every entity that defines a seedData array in ninjadog.json. The seeder is registered in the DI container and called during application startup, immediately after the database schema is initialized.

The DatabaseSeeder file is only generated when at least one entity includes a seedData array. If no entities define seed data, the file is not emitted.

Configuration

Add a seedData array to any entity in your ninjadog.json. Each element is an object whose keys match the entity’s property names.

{
  "entities": {
    "Category": {
      "properties": {
        "Id": { "type": "Guid", "isKey": true },
        "Name": { "type": "string" },
        "SortOrder": { "type": "int" },
        "IsActive": { "type": "bool" }
      },
      "seedData": [
        { "Id": "550e8400-e29b-41d4-a716-446655440001", "Name": "Electronics", "SortOrder": 1, "IsActive": true },
        { "Id": "550e8400-e29b-41d4-a716-446655440002", "Name": "Books", "SortOrder": 2, "IsActive": true },
        { "Id": "550e8400-e29b-41d4-a716-446655440003", "Name": "Archive", "SortOrder": 99, "IsActive": false }
      ]
    }
  }
}

Rules

Generated Output

Given the configuration above, Ninjadog generates:

public partial class DatabaseSeeder(IDbConnectionFactory connectionFactory)
{
    public async Task SeedAsync()
    {
        using var connection = await connectionFactory.CreateConnectionAsync();

        await connection.ExecuteAsync("INSERT INTO Categories (Id, Name, SortOrder, IsActive) VALUES ('550e8400-e29b-41d4-a716-446655440001', 'Electronics', 1, 1)");

        await connection.ExecuteAsync("INSERT INTO Categories (Id, Name, SortOrder, IsActive) VALUES ('550e8400-e29b-41d4-a716-446655440002', 'Books', 2, 1)");

        await connection.ExecuteAsync("INSERT INTO Categories (Id, Name, SortOrder, IsActive) VALUES ('550e8400-e29b-41d4-a716-446655440003', 'Archive', 99, 0)");

    }
}

Integration with DI and Startup

The DatabaseSeeder is automatically registered in the dependency injection container and invoked at startup. In the generated Program.cs and DI extensions:

  1. DI RegistrationDatabaseSeeder is registered as a singleton service in CrudWebApiExtensions.AddNinjadog().
  2. Startup CallDatabaseSeeder.SeedAsync() is called in CrudWebApiExtensions.UseNinjadog(), right after DatabaseInitializer.InitializeAsync().
// In AddNinjadog()
services.AddSingleton<DatabaseSeeder>();

// In UseNinjadog()
var initializer = app.Services.GetRequiredService<DatabaseInitializer>();
await initializer.InitializeAsync();

var seeder = app.Services.GetRequiredService<DatabaseSeeder>();
await seeder.SeedAsync();

Because DatabaseSeeder is a partial class, you can extend it with custom seeding logic in a separate file without modifying generated code.

Multiple Entities

When several entities define seed data, all INSERT statements are combined in a single DatabaseSeeder class:

{
  "entities": {
    "Category": {
      "properties": { ... },
      "seedData": [ ... ]
    },
    "Tag": {
      "properties": {
        "Id": { "type": "Guid", "isKey": true },
        "Label": { "type": "string" }
      },
      "seedData": [
        { "Id": "660e8400-0000-0000-0000-000000000001", "Label": "Featured" },
        { "Id": "660e8400-0000-0000-0000-000000000002", "Label": "Sale" }
      ]
    }
  }
}

The generated seeder includes INSERT statements for both Categories and Tags tables.


Next Steps