Add database seeding to dev env

This commit is contained in:
Aaron Po
2026-02-07 18:32:50 -05:00
parent 393e57af7f
commit 17bf29700a
8 changed files with 237 additions and 67 deletions

View File

@@ -0,0 +1,24 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["API/API.Core/API.Core.csproj", "API/API.Core/"]
COPY ["API/API.Specs/API.Specs.csproj", "API/API.Specs/"]
COPY ["Repository/Repository.Core/Repository.Core.csproj", "Repository/Repository.Core/"]
COPY ["Service/Service.Core/Service.Core.csproj", "Service/Service.Core/"]
RUN dotnet restore "API/API.Specs/API.Specs.csproj"
COPY . .
WORKDIR "/src/API/API.Specs"
RUN dotnet build "./API.Specs.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./API.Specs.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS final
WORKDIR /src
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Copy the entire source tree for testing
COPY . .
RUN mkdir -p /app/test-results
WORKDIR /src/API/API.Specs
ENTRYPOINT ["dotnet", "test", "API.Specs.csproj", "-c", "Release", "--logger", "trx;LogFileName=/app/test-results/test-results.trx"]

View File

@@ -4,7 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>DataLayer</RootNamespace>
<RootNamespace>Database.Migrations</RootNamespace>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>

View File

@@ -3,7 +3,7 @@ using System.Reflection;
using DbUp;
using Microsoft.Data.SqlClient;
namespace DataLayer;
namespace Database.Migrations;
public static class Program
{
@@ -22,6 +22,57 @@ public static class Program
return result.Successful;
}
private static bool ClearDatabase()
{
var myConn = new SqlConnection(masterConnectionString);
try
{
myConn.Open();
// First, set the database to single user mode to close all connections
var setModeCommand = new SqlCommand(
"IF EXISTS (SELECT 1 FROM sys.databases WHERE name = 'Biergarten') " +
"ALTER DATABASE [Biergarten] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;",
myConn);
try
{
setModeCommand.ExecuteNonQuery();
Console.WriteLine("Database set to single user mode.");
}
catch (System.Exception ex)
{
Console.WriteLine($"Warning: Could not set single user mode: {ex.Message}");
}
// Then drop the database
var dropCommand = new SqlCommand("DROP DATABASE IF EXISTS [Biergarten];", myConn);
try
{
dropCommand.ExecuteNonQuery();
Console.WriteLine("Database cleared successfully.");
}
catch (System.Exception ex)
{
Console.WriteLine($"Error dropping database: {ex}");
return false;
}
}
catch (System.Exception ex)
{
Console.WriteLine($"Error clearing database: {ex}");
return false;
}
finally
{
if (myConn.State == ConnectionState.Open)
{
myConn.Close();
}
}
return true;
}
private static bool CreateDatabaseIfNotExists()
{
var myConn = new SqlConnection(masterConnectionString);
@@ -58,6 +109,13 @@ public static class Program
try
{
var clearDatabase = Environment.GetEnvironmentVariable("CLEAR_DATABASE");
if (clearDatabase == "true")
{
Console.WriteLine("CLEAR_DATABASE is enabled. Clearing existing database...");
ClearDatabase();
}
CreateDatabaseIfNotExists();
var success = DeployMigrations();

View File

@@ -4,7 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>DBSeed</RootNamespace>
<RootNamespace>Database.Seed</RootNamespace>
</PropertyGroup>
<ItemGroup>
@@ -18,7 +18,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Database.Migrations\Database.Migrations.csproj" />
<ProjectReference Include="..\..\Repository\Repository.Core\Repository.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,16 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Copy everything from the context (src/Core)
COPY . .
RUN dotnet restore "./Database/Database.Seed/Database.Seed.csproj"
RUN dotnet build "./Database/Database.Seed/Database.Seed.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Database/Database.Seed/Database.Seed.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM mcr.microsoft.com/dotnet/runtime:10.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Database.Seed.dll"]

View File

@@ -5,73 +5,31 @@ using System.Reflection;
try
{
var connectionString = Environment.GetEnvironmentVariable(
"DB_CONNECTION_STRING"
);
if (string.IsNullOrWhiteSpace(connectionString))
throw new InvalidOperationException(
"Environment variable DB_CONNECTION_STRING is not set or is empty."
);
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
// drop and recreate the database
var useMaster = connection.CreateCommand();
useMaster.CommandText = "USE master;";
await useMaster.ExecuteNonQueryAsync();
var dbName = "Biergarten";
var dropDb = connection.CreateCommand();
dropDb.CommandText = $@"
IF DB_ID(N'{dbName}') IS NOT NULL
BEGIN
ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [{dbName}];
END";
await dropDb.ExecuteNonQueryAsync();
var createDb = connection.CreateCommand();
createDb.CommandText = $@"CREATE DATABASE [{dbName}];";
await createDb.ExecuteNonQueryAsync();
await connection.CloseAsync();
await connection.OpenAsync();
var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");
Console.WriteLine("Connected to database.");
Console.WriteLine("Starting seeding...");
Console.WriteLine("Starting migrations...");
// Run Database.Core migrations (embedded resources) via DbUp
var migrationAssembly = Assembly.Load("Database.Core");
var upgrader = DeployChanges
.To.SqlDatabase(connectionString)
.WithScriptsEmbeddedInAssembly(migrationAssembly)
.LogToConsole()
.Build();
var upgradeResult = upgrader.PerformUpgrade();
if (!upgradeResult.Successful)
throw upgradeResult.Error;
Console.WriteLine("Migrations completed.");
ISeeder[] seeders =
[
new LocationSeeder(),
new UserSeeder(),
];
foreach (var seeder in seeders)
using (var connection = new SqlConnection(connectionString))
{
Console.WriteLine($"Seeding {seeder.GetType().Name}...");
await seeder.SeedAsync(connection);
Console.WriteLine($"{seeder.GetType().Name} seeded.");
await connection.OpenAsync();
ISeeder[] seeders =
[
new LocationSeeder(),
new UserSeeder(),
];
foreach (var seeder in seeders)
{
Console.WriteLine($"Seeding {seeder.GetType().Name}...");
await seeder.SeedAsync(connection);
Console.WriteLine($"{seeder.GetType().Name} seeded.");
}
Console.WriteLine("Seed completed successfully.");
}
Console.WriteLine("Seed completed successfully.");
await connection.CloseAsync();
return 0;
}
catch (Exception ex)