diff --git a/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs b/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs new file mode 100644 index 0000000..a12209d --- /dev/null +++ b/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs @@ -0,0 +1,231 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Printbase.Infrastructure.Database; + +#nullable disable + +namespace Printbase.Infrastructure.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250504210542_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TypeId") + .HasColumnType("uniqueidentifier"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ProductGroups"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("GroupId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("Name", "GroupId") + .IsUnique(); + + b.ToTable("ProductTypes"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Color") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Discount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Price") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ProductId") + .HasColumnType("uniqueidentifier"); + + b.Property("SKU") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Size") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Stock") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ProductId", "Color", "Size") + .IsUnique() + .HasFilter("[Color] IS NOT NULL AND [Size] IS NOT NULL"); + + b.ToTable("ProductVariants"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => + { + b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", "Type") + .WithMany("Products") + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => + { + b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", "Group") + .WithMany("Types") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => + { + b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", "Product") + .WithMany("Variants") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => + { + b.Navigation("Variants"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => + { + b.Navigation("Types"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => + { + b.Navigation("Products"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs b/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs new file mode 100644 index 0000000..c5e1a22 --- /dev/null +++ b/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs @@ -0,0 +1,149 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Printbase.Infrastructure.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ProductGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + IsActive = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProductTypes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), + GroupId = table.Column(type: "uniqueidentifier", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + IsActive = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductTypes", x => x.Id); + table.ForeignKey( + name: "FK_ProductTypes_ProductGroups_GroupId", + column: x => x.GroupId, + principalTable: "ProductGroups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Products", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + TypeId = table.Column(type: "uniqueidentifier", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + IsActive = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Products", x => x.Id); + table.ForeignKey( + name: "FK_Products_ProductTypes_TypeId", + column: x => x.TypeId, + principalTable: "ProductTypes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "ProductVariants", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ProductId = table.Column(type: "uniqueidentifier", nullable: false), + Color = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Size = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: true), + Price = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + Discount = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), + Stock = table.Column(type: "int", nullable: false), + SKU = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + IsActive = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductVariants", x => x.Id); + table.ForeignKey( + name: "FK_ProductVariants_Products_ProductId", + column: x => x.ProductId, + principalTable: "Products", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ProductGroups_Name", + table: "ProductGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Products_TypeId", + table: "Products", + column: "TypeId"); + + migrationBuilder.CreateIndex( + name: "IX_ProductTypes_GroupId", + table: "ProductTypes", + column: "GroupId"); + + migrationBuilder.CreateIndex( + name: "IX_ProductTypes_Name_GroupId", + table: "ProductTypes", + columns: new[] { "Name", "GroupId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ProductVariants_ProductId_Color_Size", + table: "ProductVariants", + columns: new[] { "ProductId", "Color", "Size" }, + unique: true, + filter: "[Color] IS NOT NULL AND [Size] IS NOT NULL"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ProductVariants"); + + migrationBuilder.DropTable( + name: "Products"); + + migrationBuilder.DropTable( + name: "ProductTypes"); + + migrationBuilder.DropTable( + name: "ProductGroups"); + } + } +} diff --git a/src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 0000000..c26eaeb --- /dev/null +++ b/src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,228 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Printbase.Infrastructure.Database; + +#nullable disable + +namespace Printbase.Infrastructure.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TypeId") + .HasColumnType("uniqueidentifier"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ProductGroups"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("GroupId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("Name", "GroupId") + .IsUnique(); + + b.ToTable("ProductTypes"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Color") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Discount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Price") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ProductId") + .HasColumnType("uniqueidentifier"); + + b.Property("SKU") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Size") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Stock") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ProductId", "Color", "Size") + .IsUnique() + .HasFilter("[Color] IS NOT NULL AND [Size] IS NOT NULL"); + + b.ToTable("ProductVariants"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => + { + b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", "Type") + .WithMany("Products") + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => + { + b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", "Group") + .WithMany("Types") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => + { + b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", "Product") + .WithMany("Variants") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => + { + b.Navigation("Variants"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => + { + b.Navigation("Types"); + }); + + modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => + { + b.Navigation("Products"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Printbase.WebApi/Printbase.WebApi.csproj b/src/Printbase.WebApi/Printbase.WebApi.csproj index 817b7d5..b062d35 100644 --- a/src/Printbase.WebApi/Printbase.WebApi.csproj +++ b/src/Printbase.WebApi/Printbase.WebApi.csproj @@ -7,7 +7,11 @@ - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/src/Printbase.WebApi/Startup.cs b/src/Printbase.WebApi/Startup.cs index c304c66..bb593f5 100644 --- a/src/Printbase.WebApi/Startup.cs +++ b/src/Printbase.WebApi/Startup.cs @@ -7,7 +7,7 @@ using Printbase.Infrastructure.Repositories; namespace Printbase.WebApi; -public class Startup +public static class Startup { public static void ConfigureServices(WebApplicationBuilder builder) { @@ -32,6 +32,22 @@ public class Startup public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + if (app is WebApplication application) + { + using var scope = application.Services.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + try + { + dbContext.Database.Migrate(); + Console.WriteLine("Database migrations applied successfully"); + } + catch (Exception ex) + { + Console.WriteLine($"An error occurred while applying migrations: {ex.Message}"); + } + } + + if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/src/Printbase.WebApi/appsettings.Development.json b/src/Printbase.WebApi/appsettings.Development.json index 0c208ae..1ec280f 100644 --- a/src/Printbase.WebApi/appsettings.Development.json +++ b/src/Printbase.WebApi/appsettings.Development.json @@ -4,5 +4,11 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } + }, + "ConnectionStrings": { + "DefaultConnection": "Server=localhost,${SQL_PORT};Database=PrintbaseDb;User Id=sa;Password=${SA_PASSWORD};TrustServerCertificate=True;" + }, + "DatabaseOptions": { + "ApplyMigrationsAtStartup": true } -} +} \ No newline at end of file diff --git a/src/Printbase.WebApi/appsettings.json b/src/Printbase.WebApi/appsettings.json index 10f68b8..1ec280f 100644 --- a/src/Printbase.WebApi/appsettings.json +++ b/src/Printbase.WebApi/appsettings.json @@ -5,5 +5,10 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" -} + "ConnectionStrings": { + "DefaultConnection": "Server=localhost,${SQL_PORT};Database=PrintbaseDb;User Id=sa;Password=${SA_PASSWORD};TrustServerCertificate=True;" + }, + "DatabaseOptions": { + "ApplyMigrationsAtStartup": true + } +} \ No newline at end of file