Using Dapper to auto-migrate a postgres database and create the database
- code example : HERE
- create an Extension folder with a HostExtensions static class.
- inside it create a static generic method that takes the host (what configures the startup and lifetime of the app) which returns it after it’s done.- we add a retry cause when running in a docker-compose, the databse being ready isn’t a gurantee even with depends-onspecified.
 1 2 3 4 5 6 public static class HostExtensions { public static IHost MigrateDatabase<TContext>(this IHost host, int? retry = 0) { } } 
- we add a retry cause when running in a docker-compose, the databse being ready isn’t a gurantee even with 
- create a scopefromhost.Services.CreateScope()and get the required services1 2 3 4 5 6 using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; var configuration = services.GetRequiredService<IConfiguration>(); var logger = services.GetRequiredService<ILogger<TContext>>(); } 
- in there add a tryandcatchblocks, log depending on your desire and create a connection object using theusingscope so it releases (closes) the connection when it’s done.- the connection string for postgresneeds to NOT have the database name, it’ll look like this:"DatabaseSettings": { "ConnectionString": "Server=HOST;Port=PORT;User Id=USER;Password=PASS;", "DatabaseName":"db-name" <- needs to be lower case ! }
 1 2 3 4 5 6 7 8 logger.LogInformation("Migrating postresql database."); using var connection = new NpgsqlConnection(configuration.GetValue<string>("DatabaseSettings:ConnectionString")); // open the connection connection.Open(); // get the database name from `appsettings.json` or where'ver you have it string dbName = configuration["DatabaseSettings:DatabaseName"]; 
- the connection string for 
- check if the database you’re trying to create exists or not, the name of the database has to be lower case to match the one postgres will create. - 1 2 3 4 5 6 7 8 - var checkDatabaseExistsSql = $"SELECT 1 FROM pg_database WHERE datname = '{dbName}'"; var databaseExists = connection.ExecuteScalar<bool>(checkDatabaseExistsSql); if (!databaseExists) { var createDatabaseSql = $"CREATE DATABASE {dbName};"; connection.Execute(createDatabaseSql); } 
- kill the existsing connection and create a new one that’ll have the databaseyou wanna use in it, open it and create acommandobject so you can do the operations you desire:1 2 3 4 5 6 7 8 9 10 11 connection.Close(); // replace the old connection with a new one with the database using var updatedConnection = new NpgsqlConnection($"{configuration["DatabaseSettings:ConnectionString"]}Database={dbName};"); updatedConnection.Open(); using var command = new NpgsqlCommand { Connection = updatedConnection }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 command.CommandText = "DROP TABLE IF EXISTS TABLE-NAME"; command.ExecuteNonQuery(); command.CommandText = @"CREATE TABLE TABLE(Id SERIAL PRIMARY KEY, Name VARCHAR(24) NOT NULL, Description TEXT, ... )"; command.ExecuteNonQuery(); command.CommandText = "INSERT INTO TABLE_NAME(Name, Description) VALUES('STUFF', 'IN HERE');"; command.ExecuteNonQuery(); . . . logger.LogInformation("Migrated postresql database."); 
- in the catchblockwe except a NpgsqlExceptionexception and retry1 2 3 4 5 6 7 8 9 10 11 catch (NpgsqlException ex) { logger.LogError(ex, "An error occurred while migrating the postresql database"); if (retryForAvailability < 50) { retryForAvailability++; System.Threading.Thread.Sleep(2000); MigrateDatabase<TContext>(host, retryForAvailability); } } 
- finally we return the Host1 return host; 
- in Programfile, we call it providing theProgram classas the Type1 app.MigrateDatabase<Program>(); 
test it
- spin up a postgres container - 1 - docker container run -p 5432:5432 -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=admin1234 --name testgres postgres 
- create a new api project or use an open one and follow thru the steps upove 
