Initial commit - ECommerce project

This commit is contained in:
2026-08-05 23:58:33 +03:00
commit bcebac18e7
63 changed files with 4543 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
using System.Text.Json;
using Bogus;
using Commerce.Contracts.DTOs;
using Commerce.Domain.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Commerce.Domain;
public class Context : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
public Context(DbContextOptions<Context> options)
: base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
if (Database.IsNpgsql())
{
modelBuilder.Entity<Product>(entity =>
{
entity.OwnsMany(e => e.Translations, b =>
{
b.ToJson();
b.OwnsOne(t => t.Info, i =>
{
i.OwnsMany(ti => ti.TechnicalDetails);
});
});
});
modelBuilder.Entity<Category>(entity =>
{
entity.OwnsMany(e => e.Translations, b =>
{
b.ToJson();
b.OwnsOne(t => t.Info, i =>
{
i.OwnsMany(ti => ti.TechnicalDetails);
});
});
});
}
else
{
var productTranslationsConverter = new Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<List<ProductTranslation>, string>(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
v => JsonSerializer.Deserialize<List<ProductTranslation>>(v, (JsonSerializerOptions?)null) ?? new List<ProductTranslation>());
var categoryTranslationsConverter = new Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<List<CategoryTranslation>, string>(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
v => JsonSerializer.Deserialize<List<CategoryTranslation>>(v, (JsonSerializerOptions?)null) ?? new List<CategoryTranslation>());
modelBuilder.Entity<Product>(entity =>
{
entity.Property(e => e.Translations).HasConversion(productTranslationsConverter);
});
modelBuilder.Entity<Category>(entity =>
{
entity.Property(e => e.Translations).HasConversion(categoryTranslationsConverter);
});
}
}
}
+30
View File
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<!-- <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" /> -->
<!-- <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> -->
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../ECommerce.Contracts/ECommerce.Contracts.csproj" />
</ItemGroup>
</Project>
+108
View File
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Commerce.Contracts.DTOs;
namespace Commerce.Domain.Entities;
public class Category
{
public Guid Id { get; set; }
public string[] Photos { get; set; } = Array.Empty<string>();
public Guid? ParentCategoryId { get; set; }
public Category? ParentCategory { get; set; }
public ICollection<Category> ChildCategories { get; set; } = new List<Category>();
public bool IsBundle { get; set; }
// New nested structure for JSONB
public List<CategoryTranslation> Translations { get; set; } = new();
public static CategoryVM ToVM(Category category, string? language = null)
{
var translations = category.Translations?.ToList() ?? new List<CategoryTranslation>();
List<CategoryTranslationVM> selectedTranslations;
if (string.IsNullOrEmpty(language))
{
selectedTranslations = translations
.Select(t => new CategoryTranslationVM
{
Language = t.Language,
Info = new CategoryInfoVM
{
Name = t.Info.Name,
Description = t.Info.Description,
TechnicalDetails = t.Info.TechnicalDetails?.Select(td => new TechnicalDetailVM { Key = td.Key, Value = td.Value }).ToList() ?? new()
}
}).ToList();
}
else
{
var matchedTranslation = translations
.FirstOrDefault(t => t.Language == language)
?? translations.FirstOrDefault(t => t.Language == "en");
selectedTranslations = matchedTranslation != null
? new List<CategoryTranslationVM>
{
new CategoryTranslationVM
{
Language = matchedTranslation.Language,
Info = new CategoryInfoVM
{
Name = matchedTranslation.Info.Name,
Description = matchedTranslation.Info.Description,
TechnicalDetails = matchedTranslation.Info.TechnicalDetails?.Select(td => new TechnicalDetailVM { Key = td.Key, Value = td.Value }).ToList() ?? new()
}
}
}
: new List<CategoryTranslationVM>();
}
return new CategoryVM
{
Id = category.Id,
Photos = category.Photos,
ParentCategoryId = category.ParentCategoryId,
IsBundle = category.IsBundle,
Translations = selectedTranslations,
ChildCategories = category.ChildCategories?.Select(x => Category.ToVM(x, language)).ToList() ?? new List<CategoryVM>(),
};
}
public static Category ToEntity(CategoryVM categoryVM)
{
return new Category
{
Id = categoryVM.Id ?? Guid.NewGuid(),
Photos = categoryVM.Photos ?? Array.Empty<string>(),
ParentCategoryId = categoryVM.ParentCategoryId,
IsBundle = categoryVM.IsBundle,
Translations = categoryVM.Translations?.Select(t => new CategoryTranslation
{
Language = t.Language,
Info = new CategoryInfo
{
Name = t.Info.Name,
Description = t.Info.Description,
TechnicalDetails = t.Info.TechnicalDetails?.Select(td => new TechnicalDetail { Key = td.Key, Value = td.Value }).ToList() ?? new()
}
}).ToList() ?? new(),
ChildCategories = categoryVM.ChildCategories?.Select(x => Category.ToEntity(x)).ToList() ?? new List<Category>(),
};
}
}
public class CategoryTranslation
{
public string Language { get; set; } = string.Empty;
public CategoryInfo Info { get; set; } = new();
}
public class CategoryInfo
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public List<TechnicalDetail> TechnicalDetails { get; set; } = new();
}
+135
View File
@@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using Commerce.Contracts.DTOs;
namespace Commerce.Domain.Entities;
public class Product
{
public Guid Id { get; set; }
public double Price { get; set; }
public double Discount { get; set; }
public DateTime Created { get; set; }
public string CodeName { get; set; } = string.Empty;
public bool IsBundle { get; set; }
public string? CategoryName { get; set; }
public Guid? CategoryId { get; set; }
public string[] Photos { get; set; } = Array.Empty<string>();
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; } = null!;
public virtual List<Product> ChildProducts { get; set; } = new();
public virtual List<Product>? ParentBundles { get; set; }
// New nested structure for JSONB
public List<ProductTranslation> Translations { get; set; } = new();
public static ProductVM ToVM(Product product, string? language = null)
{
var translations = product.Translations?.ToList() ?? new List<ProductTranslation>();
List<ProductTranslationVM> selectedTranslations;
if (string.IsNullOrEmpty(language))
{
selectedTranslations = translations
.Select(t => new ProductTranslationVM
{
Language = t.Language,
Info = new ProductInfoVM
{
Name = t.Info.Name,
Description = t.Info.Description,
TechnicalDetails = t.Info.TechnicalDetails?.Select(td => new TechnicalDetailVM { Key = td.Key, Value = td.Value }).ToList() ?? new()
}
}).ToList();
}
else
{
var matchedTranslation = translations
.FirstOrDefault(t => t.Language == language)
?? translations.FirstOrDefault(t => t.Language == "en");
selectedTranslations = matchedTranslation != null
? new List<ProductTranslationVM>
{
new ProductTranslationVM
{
Language = matchedTranslation.Language,
Info = new ProductInfoVM
{
Name = matchedTranslation.Info.Name,
Description = matchedTranslation.Info.Description,
TechnicalDetails = matchedTranslation.Info.TechnicalDetails?.Select(td => new TechnicalDetailVM { Key = td.Key, Value = td.Value }).ToList() ?? new()
}
}
}
: new List<ProductTranslationVM>();
}
return new ProductVM
{
Id = product.Id,
Price = product.Price,
Discount = product.Discount,
Created = product.Created,
CodeName = product.CodeName,
CategoryName = product.CategoryName,
IsBundle = product.IsBundle,
CategoryId = product.CategoryId,
Photos = product.Photos,
Translations = selectedTranslations,
ChildProducts = product.ChildProducts?.Select(x => Product.ToVM(x, language)).ToList() ?? new List<ProductVM>(),
};
}
public static Product ToEntity(ProductVM productVM)
{
return new Product
{
Id = productVM.Id ?? Guid.NewGuid(),
Price = productVM.Price ?? 0,
Discount = productVM.Discount ?? 0,
Created = productVM.Created ?? DateTime.UtcNow,
CodeName = productVM.CodeName ?? string.Empty,
CategoryName = productVM.CategoryName,
IsBundle = productVM.IsBundle,
CategoryId = productVM.CategoryId ?? Guid.Empty,
Photos = productVM.Photos ?? Array.Empty<string>(),
Translations = productVM.Translations?.Select(t => new ProductTranslation
{
Language = t.Language,
Info = new ProductInfo
{
Name = t.Info.Name,
Description = t.Info.Description,
TechnicalDetails = t.Info.TechnicalDetails?.Select(td => new TechnicalDetail { Key = td.Key, Value = td.Value }).ToList() ?? new()
}
}).ToList() ?? new(),
ChildProducts = new List<Product>(),
};
}
}
public class ProductTranslation
{
public string Language { get; set; } = string.Empty;
public ProductInfo Info { get; set; } = new();
}
public class ProductInfo
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public List<TechnicalDetail> TechnicalDetails { get; set; } = new();
}
public class TechnicalDetail
{
public string Key { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
}
@@ -0,0 +1,153 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260105142147_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categorys");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<Guid?>("ProductId")
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("TechnicalDetails")
.IsRequired()
.HasColumnType("hstore");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ProductId");
b.ToTable("Products");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.Navigation("ParentCategory");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany("ChildProducts")
.HasForeignKey("ProductId");
b.Navigation("Category");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Navigation("ChildProducts");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:PostgresExtension:hstore", ",,");
migrationBuilder.CreateTable(
name: "Categorys",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Description = table.Column<string>(type: "text", nullable: false),
Photos = table.Column<string[]>(type: "text[]", nullable: false),
ParentCategoryId = table.Column<Guid>(type: "uuid", nullable: true),
IsBundle = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Categorys", x => x.Id);
table.ForeignKey(
name: "FK_Categorys_Categorys_ParentCategoryId",
column: x => x.ParentCategoryId,
principalTable: "Categorys",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Products",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Description = table.Column<string>(type: "text", nullable: false),
Photos = table.Column<string[]>(type: "text[]", nullable: false),
TechnicalDetails = table.Column<Dictionary<string, string>>(type: "hstore", nullable: false),
Price = table.Column<double>(type: "double precision", nullable: false),
Discount = table.Column<double>(type: "double precision", nullable: false),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CodeName = table.Column<string>(type: "text", nullable: false),
IsBundle = table.Column<bool>(type: "boolean", nullable: false),
CategoryName = table.Column<string>(type: "text", nullable: true),
CategoryId = table.Column<Guid>(type: "uuid", nullable: false),
ProductId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.Id);
table.ForeignKey(
name: "FK_Products_Categorys_CategoryId",
column: x => x.CategoryId,
principalTable: "Categorys",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Products_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_Categorys_ParentCategoryId",
table: "Categorys",
column: "ParentCategoryId");
migrationBuilder.CreateIndex(
name: "IX_Products_CategoryId",
table: "Products",
column: "CategoryId");
migrationBuilder.CreateIndex(
name: "IX_Products_ProductId",
table: "Products",
column: "ProductId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Products");
migrationBuilder.DropTable(
name: "Categorys");
}
}
}
@@ -0,0 +1,153 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260110093153_ModelUpdate")]
partial class ModelUpdate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<Guid?>("ProductId")
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("TechnicalDetails")
.IsRequired()
.HasColumnType("hstore");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ProductId");
b.ToTable("Products");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.Navigation("ParentCategory");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany("ChildProducts")
.HasForeignKey("ProductId");
b.Navigation("Category");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Navigation("ChildProducts");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,100 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class ModelUpdate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Categorys_Categorys_ParentCategoryId",
table: "Categorys");
migrationBuilder.DropForeignKey(
name: "FK_Products_Categorys_CategoryId",
table: "Products");
migrationBuilder.DropPrimaryKey(
name: "PK_Categorys",
table: "Categorys");
migrationBuilder.RenameTable(
name: "Categorys",
newName: "Categories");
migrationBuilder.RenameIndex(
name: "IX_Categorys_ParentCategoryId",
table: "Categories",
newName: "IX_Categories_ParentCategoryId");
migrationBuilder.AddPrimaryKey(
name: "PK_Categories",
table: "Categories",
column: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Categories_Categories_ParentCategoryId",
table: "Categories",
column: "ParentCategoryId",
principalTable: "Categories",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Products_Categories_CategoryId",
table: "Products",
column: "CategoryId",
principalTable: "Categories",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Categories_Categories_ParentCategoryId",
table: "Categories");
migrationBuilder.DropForeignKey(
name: "FK_Products_Categories_CategoryId",
table: "Products");
migrationBuilder.DropPrimaryKey(
name: "PK_Categories",
table: "Categories");
migrationBuilder.RenameTable(
name: "Categories",
newName: "Categorys");
migrationBuilder.RenameIndex(
name: "IX_Categories_ParentCategoryId",
table: "Categorys",
newName: "IX_Categorys_ParentCategoryId");
migrationBuilder.AddPrimaryKey(
name: "PK_Categorys",
table: "Categorys",
column: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Categorys_Categorys_ParentCategoryId",
table: "Categorys",
column: "ParentCategoryId",
principalTable: "Categorys",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Products_Categorys_CategoryId",
table: "Products",
column: "CategoryId",
principalTable: "Categorys",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}
@@ -0,0 +1,152 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260119105451_MultiLanguageSupport")]
partial class MultiLanguageSupport
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("Description")
.IsRequired()
.HasColumnType("jsonb");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Dictionary<string, string>>("Name")
.IsRequired()
.HasColumnType("jsonb");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<Dictionary<string, string>>("Description")
.IsRequired()
.HasColumnType("jsonb");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Dictionary<string, string>>("Name")
.IsRequired()
.HasColumnType("jsonb");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<Guid?>("ProductId")
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("TechnicalDetails")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ProductId");
b.ToTable("Products");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.Navigation("ParentCategory");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany("ChildProducts")
.HasForeignKey("ProductId");
b.Navigation("Category");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Navigation("ChildProducts");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,73 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class MultiLanguageSupport : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.OldAnnotation("Npgsql:PostgresExtension:hstore", ",,");
// Use Sql for all column type changes to include the USING clause
migrationBuilder.Sql("ALTER TABLE \"Products\" ALTER COLUMN \"TechnicalDetails\" TYPE jsonb USING \"TechnicalDetails\"::jsonb;");
migrationBuilder.Sql("ALTER TABLE \"Products\" ALTER COLUMN \"Name\" TYPE jsonb USING jsonb_build_object('en', \"Name\");");
migrationBuilder.Sql("ALTER TABLE \"Products\" ALTER COLUMN \"Description\" TYPE jsonb USING jsonb_build_object('en', \"Description\");");
migrationBuilder.Sql("ALTER TABLE \"Categories\" ALTER COLUMN \"Name\" TYPE jsonb USING jsonb_build_object('en', \"Name\");");
migrationBuilder.Sql("ALTER TABLE \"Categories\" ALTER COLUMN \"Description\" TYPE jsonb USING jsonb_build_object('en', \"Description\");");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:PostgresExtension:hstore", ",,");
migrationBuilder.AlterColumn<Dictionary<string, string>>(
name: "TechnicalDetails",
table: "Products",
type: "hstore",
nullable: false,
oldClrType: typeof(Dictionary<string, string>),
oldType: "jsonb");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Products",
type: "text",
nullable: false,
oldClrType: typeof(Dictionary<string, string>),
oldType: "jsonb");
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "Products",
type: "text",
nullable: false,
oldClrType: typeof(Dictionary<string, string>),
oldType: "jsonb");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Categories",
type: "text",
nullable: false,
oldClrType: typeof(Dictionary<string, string>),
oldType: "jsonb");
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "Categories",
type: "text",
nullable: false,
oldClrType: typeof(Dictionary<string, string>),
oldType: "jsonb");
}
}
}
@@ -0,0 +1,171 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Commerce.Contracts.DTOs;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260119121446_TechnicalDetailsForCategories")]
partial class TechnicalDetailsForCategories
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("Description")
.IsRequired()
.HasColumnType("jsonb");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Dictionary<string, string>>("Name")
.IsRequired()
.HasColumnType("jsonb");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<Dictionary<string, List<TechnicalDetail>>>("TechnicalDetails")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<Dictionary<string, string>>("Description")
.IsRequired()
.HasColumnType("jsonb");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Dictionary<string, string>>("Name")
.IsRequired()
.HasColumnType("jsonb");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<Dictionary<string, List<TechnicalDetail>>>("TechnicalDetails")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Products");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.Property<Guid>("ChildProductsId")
.HasColumnType("uuid");
b.Property<Guid>("ParentBundlesId")
.HasColumnType("uuid");
b.HasKey("ChildProductsId", "ParentBundlesId");
b.HasIndex("ParentBundlesId");
b.ToTable("ProductProduct");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.Navigation("ParentCategory");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
b.Navigation("Category");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ChildProductsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ParentBundlesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using Commerce.Contracts.DTOs;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class TechnicalDetailsForCategories : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Products_Categories_CategoryId",
table: "Products");
migrationBuilder.DropForeignKey(
name: "FK_Products_Products_ProductId",
table: "Products");
migrationBuilder.DropIndex(
name: "IX_Products_ProductId",
table: "Products");
migrationBuilder.DropColumn(
name: "ProductId",
table: "Products");
migrationBuilder.AlterColumn<Guid>(
name: "CategoryId",
table: "Products",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AddColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Categories",
type: "jsonb",
nullable: true);
migrationBuilder.CreateTable(
name: "ProductProduct",
columns: table => new
{
ChildProductsId = table.Column<Guid>(type: "uuid", nullable: false),
ParentBundlesId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductProduct", x => new { x.ChildProductsId, x.ParentBundlesId });
table.ForeignKey(
name: "FK_ProductProduct_Products_ChildProductsId",
column: x => x.ChildProductsId,
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProductProduct_Products_ParentBundlesId",
column: x => x.ParentBundlesId,
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ProductProduct_ParentBundlesId",
table: "ProductProduct",
column: "ParentBundlesId");
migrationBuilder.AddForeignKey(
name: "FK_Products_Categories_CategoryId",
table: "Products",
column: "CategoryId",
principalTable: "Categories",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Products_Categories_CategoryId",
table: "Products");
migrationBuilder.DropTable(
name: "ProductProduct");
migrationBuilder.DropColumn(
name: "TechnicalDetails",
table: "Categories");
migrationBuilder.AlterColumn<Guid>(
name: "CategoryId",
table: "Products",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AddColumn<Guid>(
name: "ProductId",
table: "Products",
type: "uuid",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Products_ProductId",
table: "Products",
column: "ProductId");
migrationBuilder.AddForeignKey(
name: "FK_Products_Categories_CategoryId",
table: "Products",
column: "CategoryId",
principalTable: "Categories",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Products_Products_ProductId",
table: "Products",
column: "ProductId",
principalTable: "Products",
principalColumn: "Id");
}
}
}
@@ -0,0 +1,169 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Commerce.Contracts.DTOs;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260119180718_MakeTechnicalDetailsNullable")]
partial class MakeTechnicalDetailsNullable
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Dictionary<string, string>>("Description")
.IsRequired()
.HasColumnType("jsonb");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Dictionary<string, string>>("Name")
.IsRequired()
.HasColumnType("jsonb");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<Dictionary<string, List<TechnicalDetail>>>("TechnicalDetails")
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<Dictionary<string, string>>("Description")
.IsRequired()
.HasColumnType("jsonb");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Dictionary<string, string>>("Name")
.IsRequired()
.HasColumnType("jsonb");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<Dictionary<string, List<TechnicalDetail>>>("TechnicalDetails")
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Products");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.Property<Guid>("ChildProductsId")
.HasColumnType("uuid");
b.Property<Guid>("ParentBundlesId")
.HasColumnType("uuid");
b.HasKey("ChildProductsId", "ParentBundlesId");
b.HasIndex("ParentBundlesId");
b.ToTable("ProductProduct");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.Navigation("ParentCategory");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
b.Navigation("Category");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ChildProductsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ParentBundlesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,54 @@
using System.Collections.Generic;
using Commerce.Contracts.DTOs;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class MakeTechnicalDetailsNullable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Products",
type: "jsonb",
nullable: true,
oldClrType: typeof(Dictionary<string, List<TechnicalDetail>>),
oldType: "jsonb");
migrationBuilder.AlterColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Categories",
type: "jsonb",
nullable: true,
oldClrType: typeof(Dictionary<string, List<TechnicalDetail>>),
oldType: "jsonb");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Products",
type: "jsonb",
nullable: false,
oldClrType: typeof(Dictionary<string, List<TechnicalDetail>>),
oldType: "jsonb",
oldNullable: true);
migrationBuilder.AlterColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Categories",
type: "jsonb",
nullable: false,
oldClrType: typeof(Dictionary<string, List<TechnicalDetail>>),
oldType: "jsonb",
oldNullable: true);
}
}
}
@@ -0,0 +1,155 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Commerce.Domain;
using Commerce.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260120122747_NestedTranslations")]
partial class NestedTranslations
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<List<CategoryTranslation>>("Translations")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<List<ProductTranslation>>("Translations")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Products");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.Property<Guid>("ChildProductsId")
.HasColumnType("uuid");
b.Property<Guid>("ParentBundlesId")
.HasColumnType("uuid");
b.HasKey("ChildProductsId", "ParentBundlesId");
b.HasIndex("ParentBundlesId");
b.ToTable("ProductProduct");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.Navigation("ParentCategory");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
b.Navigation("Category");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ChildProductsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ParentBundlesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,118 @@
using System.Collections.Generic;
using Commerce.Contracts.DTOs;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class NestedTranslations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "Name",
table: "Products",
newName: "Translations");
migrationBuilder.RenameColumn(
name: "Name",
table: "Categories",
newName: "Translations");
// Data Transformation for Products
migrationBuilder.Sql(@"
UPDATE ""Products""
SET ""Translations"" = (
SELECT jsonb_agg(
jsonb_build_object(
'Language', key,
'Info', jsonb_build_object(
'Name', value,
'Description', COALESCE(""Description""->>key, ''),
'TechnicalDetails', COALESCE(""TechnicalDetails""->key, '[]'::jsonb)
)
)
)
FROM jsonb_each_text(""Translations"")
)
WHERE jsonb_typeof(""Translations"") = 'object';
");
// Data Transformation for Categories
migrationBuilder.Sql(@"
UPDATE ""Categories""
SET ""Translations"" = (
SELECT jsonb_agg(
jsonb_build_object(
'Language', key,
'Info', jsonb_build_object(
'Name', value,
'Description', COALESCE(""Description""->>key, ''),
'TechnicalDetails', COALESCE(""TechnicalDetails""->key, '[]'::jsonb)
)
)
)
FROM jsonb_each_text(""Translations"")
)
WHERE jsonb_typeof(""Translations"") = 'object';
");
migrationBuilder.DropColumn(
name: "Description",
table: "Products");
migrationBuilder.DropColumn(
name: "TechnicalDetails",
table: "Products");
migrationBuilder.DropColumn(
name: "Description",
table: "Categories");
migrationBuilder.DropColumn(
name: "TechnicalDetails",
table: "Categories");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "Translations",
table: "Products",
newName: "Name");
migrationBuilder.RenameColumn(
name: "Translations",
table: "Categories",
newName: "Name");
migrationBuilder.AddColumn<Dictionary<string, string>>(
name: "Description",
table: "Products",
type: "jsonb",
nullable: false);
migrationBuilder.AddColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Products",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<Dictionary<string, string>>(
name: "Description",
table: "Categories",
type: "jsonb",
nullable: false);
migrationBuilder.AddColumn<Dictionary<string, List<TechnicalDetail>>>(
name: "TechnicalDetails",
table: "Categories",
type: "jsonb",
nullable: true);
}
}
}
@@ -0,0 +1,309 @@
// <auto-generated />
using System;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
[Migration("20260120132648_QueryableTranslations")]
partial class QueryableTranslations
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Products");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.Property<Guid>("ChildProductsId")
.HasColumnType("uuid");
b.Property<Guid>("ParentBundlesId")
.HasColumnType("uuid");
b.HasKey("ChildProductsId", "ParentBundlesId");
b.HasIndex("ParentBundlesId");
b.ToTable("ProductProduct");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.OwnsMany("Commerce.Domain.Entities.CategoryTranslation", "Translations", b1 =>
{
b1.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b1.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b1.Property<string>("Language")
.IsRequired()
.HasColumnType("text");
b1.HasKey("CategoryId", "__synthesizedOrdinal");
b1.ToTable("Categories");
b1.ToJson("Translations");
b1.WithOwner()
.HasForeignKey("CategoryId");
b1.OwnsOne("Commerce.Domain.Entities.CategoryInfo", "Info", b2 =>
{
b2.Property<Guid>("CategoryTranslationCategoryId")
.HasColumnType("uuid");
b2.Property<int>("CategoryTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b2.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b2.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b2.HasKey("CategoryTranslationCategoryId", "CategoryTranslation__synthesizedOrdinal");
b2.ToTable("Categories");
b2.WithOwner()
.HasForeignKey("CategoryTranslationCategoryId", "CategoryTranslation__synthesizedOrdinal");
b2.OwnsMany("Commerce.Domain.Entities.TechnicalDetail", "TechnicalDetails", b3 =>
{
b3.Property<Guid>("CategoryInfoCategoryTranslationCategoryId")
.HasColumnType("uuid");
b3.Property<int>("CategoryInfoCategoryTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b3.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b3.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b3.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b3.HasKey("CategoryInfoCategoryTranslationCategoryId", "CategoryInfoCategoryTranslation__synthesizedOrdinal", "__synthesizedOrdinal");
b3.ToTable("Categories");
b3.WithOwner()
.HasForeignKey("CategoryInfoCategoryTranslationCategoryId", "CategoryInfoCategoryTranslation__synthesizedOrdinal");
});
b2.Navigation("TechnicalDetails");
});
b1.Navigation("Info")
.IsRequired();
});
b.Navigation("ParentCategory");
b.Navigation("Translations");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
b.OwnsMany("Commerce.Domain.Entities.ProductTranslation", "Translations", b1 =>
{
b1.Property<Guid>("ProductId")
.HasColumnType("uuid");
b1.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b1.Property<string>("Language")
.IsRequired()
.HasColumnType("text");
b1.HasKey("ProductId", "__synthesizedOrdinal");
b1.ToTable("Products");
b1.ToJson("Translations");
b1.WithOwner()
.HasForeignKey("ProductId");
b1.OwnsOne("Commerce.Domain.Entities.ProductInfo", "Info", b2 =>
{
b2.Property<Guid>("ProductTranslationProductId")
.HasColumnType("uuid");
b2.Property<int>("ProductTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b2.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b2.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b2.HasKey("ProductTranslationProductId", "ProductTranslation__synthesizedOrdinal");
b2.ToTable("Products");
b2.WithOwner()
.HasForeignKey("ProductTranslationProductId", "ProductTranslation__synthesizedOrdinal");
b2.OwnsMany("Commerce.Domain.Entities.TechnicalDetail", "TechnicalDetails", b3 =>
{
b3.Property<Guid>("ProductInfoProductTranslationProductId")
.HasColumnType("uuid");
b3.Property<int>("ProductInfoProductTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b3.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b3.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b3.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b3.HasKey("ProductInfoProductTranslationProductId", "ProductInfoProductTranslation__synthesizedOrdinal", "__synthesizedOrdinal");
b3.ToTable("Products");
b3.WithOwner()
.HasForeignKey("ProductInfoProductTranslationProductId", "ProductInfoProductTranslation__synthesizedOrdinal");
});
b2.Navigation("TechnicalDetails");
});
b1.Navigation("Info")
.IsRequired();
});
b.Navigation("Category");
b.Navigation("Translations");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ChildProductsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ParentBundlesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,54 @@
using System.Collections.Generic;
using Commerce.Domain.Entities;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Commerce.Domain.Migrations
{
/// <inheritdoc />
public partial class QueryableTranslations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Translations",
table: "Products",
type: "jsonb",
nullable: true,
oldClrType: typeof(List<ProductTranslation>),
oldType: "jsonb");
migrationBuilder.AlterColumn<string>(
name: "Translations",
table: "Categories",
type: "jsonb",
nullable: true,
oldClrType: typeof(List<CategoryTranslation>),
oldType: "jsonb");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<List<ProductTranslation>>(
name: "Translations",
table: "Products",
type: "jsonb",
nullable: false,
oldClrType: typeof(string),
oldType: "jsonb",
oldNullable: true);
migrationBuilder.AlterColumn<List<CategoryTranslation>>(
name: "Translations",
table: "Categories",
type: "jsonb",
nullable: false,
oldClrType: typeof(string),
oldType: "jsonb",
oldNullable: true);
}
}
}
@@ -0,0 +1,306 @@
// <auto-generated />
using System;
using Commerce.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Commerce.Domain.Migrations
{
[DbContext(typeof(Context))]
partial class ContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.Property<Guid?>("ParentCategoryId")
.HasColumnType("uuid");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.HasKey("Id");
b.HasIndex("ParentCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CategoryId")
.HasColumnType("uuid");
b.Property<string>("CategoryName")
.HasColumnType("text");
b.Property<string>("CodeName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<double>("Discount")
.HasColumnType("double precision");
b.Property<bool>("IsBundle")
.HasColumnType("boolean");
b.PrimitiveCollection<string[]>("Photos")
.IsRequired()
.HasColumnType("text[]");
b.Property<double>("Price")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Products");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.Property<Guid>("ChildProductsId")
.HasColumnType("uuid");
b.Property<Guid>("ParentBundlesId")
.HasColumnType("uuid");
b.HasKey("ChildProductsId", "ParentBundlesId");
b.HasIndex("ParentBundlesId");
b.ToTable("ProductProduct");
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "ParentCategory")
.WithMany("ChildCategories")
.HasForeignKey("ParentCategoryId");
b.OwnsMany("Commerce.Domain.Entities.CategoryTranslation", "Translations", b1 =>
{
b1.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b1.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b1.Property<string>("Language")
.IsRequired()
.HasColumnType("text");
b1.HasKey("CategoryId", "__synthesizedOrdinal");
b1.ToTable("Categories");
b1.ToJson("Translations");
b1.WithOwner()
.HasForeignKey("CategoryId");
b1.OwnsOne("Commerce.Domain.Entities.CategoryInfo", "Info", b2 =>
{
b2.Property<Guid>("CategoryTranslationCategoryId")
.HasColumnType("uuid");
b2.Property<int>("CategoryTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b2.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b2.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b2.HasKey("CategoryTranslationCategoryId", "CategoryTranslation__synthesizedOrdinal");
b2.ToTable("Categories");
b2.WithOwner()
.HasForeignKey("CategoryTranslationCategoryId", "CategoryTranslation__synthesizedOrdinal");
b2.OwnsMany("Commerce.Domain.Entities.TechnicalDetail", "TechnicalDetails", b3 =>
{
b3.Property<Guid>("CategoryInfoCategoryTranslationCategoryId")
.HasColumnType("uuid");
b3.Property<int>("CategoryInfoCategoryTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b3.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b3.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b3.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b3.HasKey("CategoryInfoCategoryTranslationCategoryId", "CategoryInfoCategoryTranslation__synthesizedOrdinal", "__synthesizedOrdinal");
b3.ToTable("Categories");
b3.WithOwner()
.HasForeignKey("CategoryInfoCategoryTranslationCategoryId", "CategoryInfoCategoryTranslation__synthesizedOrdinal");
});
b2.Navigation("TechnicalDetails");
});
b1.Navigation("Info")
.IsRequired();
});
b.Navigation("ParentCategory");
b.Navigation("Translations");
});
modelBuilder.Entity("Commerce.Domain.Entities.Product", b =>
{
b.HasOne("Commerce.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
b.OwnsMany("Commerce.Domain.Entities.ProductTranslation", "Translations", b1 =>
{
b1.Property<Guid>("ProductId")
.HasColumnType("uuid");
b1.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b1.Property<string>("Language")
.IsRequired()
.HasColumnType("text");
b1.HasKey("ProductId", "__synthesizedOrdinal");
b1.ToTable("Products");
b1.ToJson("Translations");
b1.WithOwner()
.HasForeignKey("ProductId");
b1.OwnsOne("Commerce.Domain.Entities.ProductInfo", "Info", b2 =>
{
b2.Property<Guid>("ProductTranslationProductId")
.HasColumnType("uuid");
b2.Property<int>("ProductTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b2.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b2.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b2.HasKey("ProductTranslationProductId", "ProductTranslation__synthesizedOrdinal");
b2.ToTable("Products");
b2.WithOwner()
.HasForeignKey("ProductTranslationProductId", "ProductTranslation__synthesizedOrdinal");
b2.OwnsMany("Commerce.Domain.Entities.TechnicalDetail", "TechnicalDetails", b3 =>
{
b3.Property<Guid>("ProductInfoProductTranslationProductId")
.HasColumnType("uuid");
b3.Property<int>("ProductInfoProductTranslation__synthesizedOrdinal")
.HasColumnType("integer");
b3.Property<int>("__synthesizedOrdinal")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b3.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b3.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b3.HasKey("ProductInfoProductTranslationProductId", "ProductInfoProductTranslation__synthesizedOrdinal", "__synthesizedOrdinal");
b3.ToTable("Products");
b3.WithOwner()
.HasForeignKey("ProductInfoProductTranslationProductId", "ProductInfoProductTranslation__synthesizedOrdinal");
});
b2.Navigation("TechnicalDetails");
});
b1.Navigation("Info")
.IsRequired();
});
b.Navigation("Category");
b.Navigation("Translations");
});
modelBuilder.Entity("ProductProduct", b =>
{
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ChildProductsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Commerce.Domain.Entities.Product", null)
.WithMany()
.HasForeignKey("ParentBundlesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Commerce.Domain.Entities.Category", b =>
{
b.Navigation("ChildCategories");
});
#pragma warning restore 612, 618
}
}
}