From 2d0606b3ef2e3522375c852c537a236e51b251cd Mon Sep 17 00:00:00 2001
From: Hutch79 <42042811+Hutch79@users.noreply.github.com>
Date: Wed, 3 Jul 2024 21:36:23 +0200
Subject: [PATCH] Added DbContext and Migrations Management Script (#4)
Fix #3
---
API/API.csproj | 10 ++
API/Program.cs | 16 ++++
Domain/Domain.csproj | 4 +
Domain/Domains.cs | 1 +
Domain/Subdomains.cs | 1 +
Domain/User.cs | 1 +
Infrastructure/Infrastructure.csproj | 30 ++++++
...240703191648_initial-migration.Designer.cs | 96 +++++++++++++++++++
.../20240703191648_initial-migration.cs | 76 +++++++++++++++
.../YourLabDbContextModelSnapshot.cs | 93 ++++++++++++++++++
Infrastructure/YourLabDbContext.cs | 39 ++++++++
Your-Lab.sln | 10 +-
scripts/dbScript.ps1 | 91 ++++++++++++++++++
13 files changed, 466 insertions(+), 2 deletions(-)
create mode 100644 Infrastructure/Infrastructure.csproj
create mode 100644 Infrastructure/Migrations/20240703191648_initial-migration.Designer.cs
create mode 100644 Infrastructure/Migrations/20240703191648_initial-migration.cs
create mode 100644 Infrastructure/Migrations/YourLabDbContextModelSnapshot.cs
create mode 100644 Infrastructure/YourLabDbContext.cs
create mode 100644 scripts/dbScript.ps1
diff --git a/API/API.csproj b/API/API.csproj
index 709f5d2..8e37bcc 100644
--- a/API/API.csproj
+++ b/API/API.csproj
@@ -6,9 +6,15 @@
enable
Your_Lab
Linux
+ 456c6c86-04fa-4b03-b088-81fcf2fb5760
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -18,4 +24,8 @@
+
+
+
+
diff --git a/API/Program.cs b/API/Program.cs
index 20cd2f5..b7e0905 100644
--- a/API/Program.cs
+++ b/API/Program.cs
@@ -1,3 +1,6 @@
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
@@ -7,8 +10,20 @@
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
+builder.Services.AddDbContext(context =>
+{
+ context.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
+ var connectionString = builder.Configuration.GetConnectionString("SqlConnectionString");
+ context.UseSqlServer(connectionString);
+});
+
var app = builder.Build();
+using var scope = app.Services.CreateScope();
+
+var context = scope.ServiceProvider.GetRequiredService();
+context.Database.Migrate();
+
// Configure the HTTP request pipeline.
// if (app.Environment.IsDevelopment())
// {
@@ -18,6 +33,7 @@
app.UseHttpsRedirection();
+// app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
diff --git a/Domain/Domain.csproj b/Domain/Domain.csproj
index 3a63532..9b2515f 100644
--- a/Domain/Domain.csproj
+++ b/Domain/Domain.csproj
@@ -6,4 +6,8 @@
enable
+
+
+
+
diff --git a/Domain/Domains.cs b/Domain/Domains.cs
index f41f29e..5ef0ba0 100644
--- a/Domain/Domains.cs
+++ b/Domain/Domains.cs
@@ -2,6 +2,7 @@ namespace Domain;
public class Domains
{
+ public int Id { get; set; }
public required string Domain { get; set; }
public required bool Active { get; set; }
}
\ No newline at end of file
diff --git a/Domain/Subdomains.cs b/Domain/Subdomains.cs
index 3bfcfec..9b39778 100644
--- a/Domain/Subdomains.cs
+++ b/Domain/Subdomains.cs
@@ -2,6 +2,7 @@ namespace Domain;
public class Subdomains
{
+ public int Id { get; set; }
public required int DomainId { get; set; }
public required int UserId { get; set; }
public required string SubdomainName { get; set; }
diff --git a/Domain/User.cs b/Domain/User.cs
index c82de82..ffd1012 100644
--- a/Domain/User.cs
+++ b/Domain/User.cs
@@ -2,6 +2,7 @@ namespace Domain;
public class User
{
+ public int Id { get; set; }
public required string Email { get; set; }
public required string Username { get; set; }
diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj
new file mode 100644
index 0000000..0110fc1
--- /dev/null
+++ b/Infrastructure/Infrastructure.csproj
@@ -0,0 +1,30 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Infrastructure/Migrations/20240703191648_initial-migration.Designer.cs b/Infrastructure/Migrations/20240703191648_initial-migration.Designer.cs
new file mode 100644
index 0000000..9a7d82f
--- /dev/null
+++ b/Infrastructure/Migrations/20240703191648_initial-migration.Designer.cs
@@ -0,0 +1,96 @@
+//
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(YourLabDbContext))]
+ [Migration("20240703191648_initial-migration")]
+ partial class initialmigration
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.6")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Domains", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Active")
+ .HasColumnType("bit");
+
+ b.Property("Domain")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Domains");
+ });
+
+ modelBuilder.Entity("Domain.Subdomains", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("DomainId")
+ .HasColumnType("int");
+
+ b.Property("SubdomainName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.ToTable("Subdomains");
+ });
+
+ modelBuilder.Entity("Domain.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Email")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Email")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Infrastructure/Migrations/20240703191648_initial-migration.cs b/Infrastructure/Migrations/20240703191648_initial-migration.cs
new file mode 100644
index 0000000..b84005d
--- /dev/null
+++ b/Infrastructure/Migrations/20240703191648_initial-migration.cs
@@ -0,0 +1,76 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ ///
+ public partial class initialmigration : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Domains",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Domain = table.Column(type: "nvarchar(max)", nullable: false),
+ Active = table.Column(type: "bit", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Domains", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Subdomains",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ DomainId = table.Column(type: "int", nullable: false),
+ UserId = table.Column(type: "int", nullable: false),
+ SubdomainName = table.Column(type: "nvarchar(max)", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Subdomains", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Users",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Email = table.Column(type: "nvarchar(450)", nullable: false),
+ Username = table.Column(type: "nvarchar(max)", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Users", x => x.Id);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Users_Email",
+ table: "Users",
+ column: "Email",
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Domains");
+
+ migrationBuilder.DropTable(
+ name: "Subdomains");
+
+ migrationBuilder.DropTable(
+ name: "Users");
+ }
+ }
+}
diff --git a/Infrastructure/Migrations/YourLabDbContextModelSnapshot.cs b/Infrastructure/Migrations/YourLabDbContextModelSnapshot.cs
new file mode 100644
index 0000000..dfcab13
--- /dev/null
+++ b/Infrastructure/Migrations/YourLabDbContextModelSnapshot.cs
@@ -0,0 +1,93 @@
+//
+using Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Infrastructure.Migrations
+{
+ [DbContext(typeof(YourLabDbContext))]
+ partial class YourLabDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.6")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Domains", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Active")
+ .HasColumnType("bit");
+
+ b.Property("Domain")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Domains");
+ });
+
+ modelBuilder.Entity("Domain.Subdomains", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("DomainId")
+ .HasColumnType("int");
+
+ b.Property("SubdomainName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.ToTable("Subdomains");
+ });
+
+ modelBuilder.Entity("Domain.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Email")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Email")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Infrastructure/YourLabDbContext.cs b/Infrastructure/YourLabDbContext.cs
new file mode 100644
index 0000000..e1bd794
--- /dev/null
+++ b/Infrastructure/YourLabDbContext.cs
@@ -0,0 +1,39 @@
+using Domain;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+
+namespace Infrastructure
+{
+ public class YourLabDbContext : DbContext
+ {
+ public YourLabDbContext(DbContextOptions options) : base(options)
+ {
+ }
+
+
+ public DbSet Users { get; set; }
+ public DbSet Domains { get; set; }
+ public DbSet Subdomains { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(YourLabDbContext).Assembly);
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity()
+ .HasIndex(u => u.Email)
+ .IsUnique(true);
+ }
+ }
+
+ public class YourLabDbContextFactory : IDesignTimeDbContextFactory
+ {
+ public YourLabDbContext CreateDbContext(string[] args)
+ {
+ var optionsBuilder = new DbContextOptionsBuilder();
+ optionsBuilder.UseSqlServer();
+
+ return new YourLabDbContext(optionsBuilder.Options);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Your-Lab.sln b/Your-Lab.sln
index 63f6842..4b7afca 100644
--- a/Your-Lab.sln
+++ b/Your-Lab.sln
@@ -9,9 +9,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "Domain\Domain.csproj", "{7B6A4E3E-5108-4AE8-9E5E-45EF20D47725}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{6919D8D5-7155-4657-9151-02FFC416C1D7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{2F42A92F-2EAE-411E-8C16-3B977BC1653C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{D02740CA-C98F-4080-8161-55D648F28D75}"
ProjectSection(SolutionItems) = preProject
- docker-compose.yml = docker-compose.yml
+ scripts\dbScript.ps1 = scripts\dbScript.ps1
EndProjectSection
EndProject
Global
@@ -28,5 +30,9 @@ Global
{7B6A4E3E-5108-4AE8-9E5E-45EF20D47725}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B6A4E3E-5108-4AE8-9E5E-45EF20D47725}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B6A4E3E-5108-4AE8-9E5E-45EF20D47725}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2F42A92F-2EAE-411E-8C16-3B977BC1653C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2F42A92F-2EAE-411E-8C16-3B977BC1653C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F42A92F-2EAE-411E-8C16-3B977BC1653C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2F42A92F-2EAE-411E-8C16-3B977BC1653C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/scripts/dbScript.ps1 b/scripts/dbScript.ps1
new file mode 100644
index 0000000..5a85e77
--- /dev/null
+++ b/scripts/dbScript.ps1
@@ -0,0 +1,91 @@
+param(
+ [switch]$displayHelp,
+ [switch]$runMigration,
+ [switch]$removeMigrationDirectory,
+ [switch]$recreateDatabase
+)
+
+function Display-UsageInstructions {
+ Write-Host ""
+ Write-Host "Usage: .\DatabaseScript.ps1 [-runMigration] [-removeMigrationDirectory] [-recreateDatabase] [-displayHelp]"
+ Write-Host "Parameters:"
+ Write-Host " -runMigration Execute the migration script."
+ Write-Host " -removeMigrationDirectory Remove the migration directory before executing the script."
+ Write-Host " -recreateDatabase Recreate the database."
+ Write-Host " -displayHelp Display this help message."
+ Write-Host ""
+}
+
+if (($PSBoundParameters.Count -eq 0) -or $displayHelp) {
+ Display-UsageInstructions
+ exit
+}
+
+if ($recreateDatabase) {
+
+ Write-Host ""
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host " CLOSING ALL CONNECTIONS"
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host ""
+
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "ALTER DATABASE Your-Lab_DB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;"
+
+ Write-Host ""
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host " RECREATING DATABASE"
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host ""
+
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "USE master; DROP DATABASE Your-Lab_DB;"
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "GO"
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "EXIT"
+
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "CREATE DATABASE Your-Lab_DB;"
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "GO"
+ sqlcmd -S "(LocalDB)\MSSQLLocalDB" -Q "EXIT"
+}
+
+if($removeMigrationDirectory) {
+ $directoryPath = "..\Infrastructure\Migrations"
+
+ Write-Host ""
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host " DELETING MIGRATION FOLDER"
+ Write-Host "==================================================" -ForegroundColor Blue
+
+ if (Test-Path -Path $directoryPath -PathType Container) {
+ Write-Host ""
+ Write-Host "Deleting directory:"
+ Write-Host "$directoryPath"
+ Remove-Item -Path $directoryPath -Recurse -Force
+ Write-Host ""
+ Write-Host "Directory deleted successfully."
+ } else {
+ Write-Host ""
+ Write-Host "Directory not found:"
+ Write-Host "$directoryPath"
+ }
+}
+
+if($runMigration) {
+ Write-Host ""
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host " CREATING MIGRATION"
+ Write-Host "==================================================" -ForegroundColor Blue
+ Write-Host ""
+
+ $MigrationName = Read-Host "Please enter the Migration name"
+
+ Set-Location -Path "..\Infrastructure"
+
+ dotnet ef migrations add $MigrationName
+
+ Set-Location -Path "..\scripts"
+}
+
+Write-Host ""
+Write-Host "==================================================" -ForegroundColor Blue
+Write-Host " COMPLETED"
+Write-Host "==================================================" -ForegroundColor Blue
+Write-Host ""
\ No newline at end of file