Refactor and enhance product and order handling

- Updated `DiscountActionDialogBoxViewModel` and `FastProductCreateDialogBoxViewModel` to create command objects directly from properties and improved error handling.
- Added meta tag management UI and logic in `ProductActionDialogBox.razor` and `ProductActionDialogBoxViewModel`.
- Increased max file read stream size to 8 MB in `StorageDialogBoxViewModel`.
- Incremented `AssemblyVersion` and `FileVersion` to `1.7.20.34` in `Netina.AdminPanel.PWA.csproj`.
- Updated `BrandsPage.razor` and `BrandsPageViewModel` for pagination and service injection.
- Updated `CategoriesPageViewModel` to create command objects directly from properties.
- Updated `ProductsPage.razor` for service injection and added a button for product details.
- Updated `ICrudApiRest` and `ICrudDtoApiRest` interfaces to use generic `Create` methods.
- Updated `appsettings.Development.json` for `StorageBaseUrl` and commented out `IsShop`.
- Added new project `AppHost.csproj` targeting .NET 8.0 with Aspire hosting.
- Added new `appsettings.Development.json` and `appsettings.json` for logging.
- Added new `Program.cs` to create and run a distributed application.
- Added new `launchSettings.json` for application launch settings.
- Added `Extensions.cs` for common .NET Aspire services.
- Added new project `ServiceDefaults.csproj` for shared service defaults.
- Introduced `ProductMetaTag` class and related migration for meta tag handling.
- Updated `OrderController.cs` for additional authorization requirements.
- Updated target frameworks to `net8.0` in various projects.
- Enhanced `SiteMapService.cs` to include brand site maps.
- Added new properties to DTOs for customer and meta tag handling.
- Enhanced `Product` class with meta tag management methods.
- Refactored `OrderMapper.g.cs` and `ProductMapper.g.cs` for improved mapping logic.
- Enhanced command handlers to manage meta tags.
- Added `ICurrentUserService` for user permissions in query handlers.
- Refactored `StorageService.cs` for paginated storage file fetching.
subProduct
Amir Hossein Khademi 2024-12-06 17:37:41 +03:30
parent 82f9d604da
commit 53dc2eac0c
26 changed files with 3401 additions and 890 deletions

View File

@ -1 +1 @@
1.6.18.28 1.7.20.34

View File

@ -16,7 +16,10 @@ public class OrderController : ICarterModule
group.MapGet("{id}", GetAsync) group.MapGet("{id}", GetAsync)
.WithDisplayName("Get Order") .WithDisplayName("Get Order")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ViewAllOrders, ApplicationPermission.ManageOrders)) .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission,
ApplicationPermission.ViewAllOrders,
ApplicationPermission.ManageOrders,
ApplicationPermission.ViewMineOrders))
.HasApiVersion(1.0); .HasApiVersion(1.0);
group.MapPost("{id}/confirm", ConfirmOrderStepAsync) group.MapPost("{id}/confirm", ConfirmOrderStepAsync)

View File

@ -6,8 +6,8 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<AssemblyVersion>1.6.18.28</AssemblyVersion> <AssemblyVersion>1.7.20.34</AssemblyVersion>
<FileVersion>1.6.18.28</FileVersion> <FileVersion>1.7.20.34</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<!--<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@ -12,9 +12,9 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" />
</ItemGroup>--> </ItemGroup>
<PropertyGroup> <!--<PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<LangVersion>10</LangVersion> <LangVersion>10</LangVersion>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@ -25,7 +25,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
</ItemGroup> </ItemGroup>-->
<ItemGroup> <ItemGroup>
<Using Include="MD.PersianDateTime.Standard" /> <Using Include="MD.PersianDateTime.Standard" />

View File

@ -99,7 +99,7 @@ public class SiteMapService(
await CreateCategoriesSiteMapsAsync(); await CreateCategoriesSiteMapsAsync();
await CreateProductsSiteMapsAsync(); await CreateProductsSiteMapsAsync();
await CreateBlogsSiteMapsAsync(); await CreateBlogsSiteMapsAsync();
//await CreateBrandsSiteMapsAsync(); await CreateBrandsSiteMapsAsync();
await CreateBlogCategoriesSiteMapsAsync(); await CreateBlogCategoriesSiteMapsAsync();
await CreatePagesSiteMapsAsync(); await CreatePagesSiteMapsAsync();

View File

@ -19,6 +19,7 @@ public class OrderLDto : BaseDto<OrderLDto,Order>
public string DiscountCode { get; set; } = string.Empty; public string DiscountCode { get; set; } = string.Empty;
public long TotalPriceWithoutDiscount => TotalPrice + DiscountPrice; public long TotalPriceWithoutDiscount => TotalPrice + DiscountPrice;
public Guid CustomerId { get; set; }
public string CustomerFullName { get; set; } = string.Empty; public string CustomerFullName { get; set; } = string.Empty;
public string CustomerPhoneNumber { get; set; } = string.Empty; public string CustomerPhoneNumber { get; set; } = string.Empty;

View File

@ -30,6 +30,7 @@ public class ProductLDto : BaseDto<ProductLDto,Product>
public List<SpecificationSDto> Specifications { get; set; } = new(); public List<SpecificationSDto> Specifications { get; set; } = new();
public List<StorageFileSDto> Files { get; set; } = new(); public List<StorageFileSDto> Files { get; set; } = new();
public List<MetaTagSDto> MetaTags { get; set; } = new();
public DiscountSDto? SpecialOffer { get; set; } public DiscountSDto? SpecialOffer { get; set; }
public Guid AuthorId { get; set; } public Guid AuthorId { get; set; }

View File

@ -21,4 +21,5 @@ public class OrderSDto : BaseDto<OrderSDto, Order>
public string CustomerFullName { get; set; } = string.Empty; public string CustomerFullName { get; set; } = string.Empty;
public string CustomerPhoneNumber { get; set; } = string.Empty; public string CustomerPhoneNumber { get; set; } = string.Empty;
public Guid CustomerId { get; set; } public Guid CustomerId { get; set; }
public string DeliveryTrackingCode { get; set; } = string.Empty;
} }

View File

@ -6,6 +6,7 @@ public partial class ProductCategoryMetaTag : MetaTag
{ {
} }
public ProductCategoryMetaTag(string type, string value, Guid productCategoryId) : base(type, value) public ProductCategoryMetaTag(string type, string value, Guid productCategoryId) : base(type, value)
{ {
ProductCategoryId = productCategoryId; ProductCategoryId = productCategoryId;

View File

@ -60,6 +60,9 @@ public partial class Product
Specifications.Add(ent); Specifications.Add(ent);
return ent; return ent;
} }
public void AddMetaTag(string key, string value)
=> MetaTags.Add(ProductMetaTag.Create(key, value, Id));
} }
public partial class ProductComment public partial class ProductComment
@ -67,6 +70,11 @@ public partial class ProductComment
public static ProductComment Create(string title, string content, float rate, bool isBuyer, bool isAdmin, Guid userId, Guid productId) public static ProductComment Create(string title, string content, float rate, bool isBuyer, bool isAdmin, Guid userId, Guid productId)
=> new(title, content, rate, isBuyer, isAdmin, userId, productId); => new(title, content, rate, isBuyer, isAdmin, userId, productId);
} }
public partial class ProductMetaTag
{
public static ProductMetaTag Create(string key, string value, Guid productId)
=> new ProductMetaTag(key, value, productId);
}
public partial class ProductStorageFile public partial class ProductStorageFile
{ {

View File

@ -85,5 +85,7 @@ public partial class Product : ApiEntity
public List<ProductComment> Comments { get; internal set; } = new(); public List<ProductComment> Comments { get; internal set; } = new();
public List<ProductStorageFile> Files { get; internal set; } = new(); public List<ProductStorageFile> Files { get; internal set; } = new();
public List<ProductMetaTag> MetaTags { get; internal set; } = new();
public List<OrderProduct> OrderProducts { get; internal set; } = new(); public List<OrderProduct> OrderProducts { get; internal set; } = new();
} }

View File

@ -0,0 +1,17 @@
namespace Netina.Domain.Entities.Products;
public partial class ProductMetaTag : MetaTag
{
public ProductMetaTag()
{
}
public ProductMetaTag(string type, string value, Guid productId) : base(type, value)
{
ProductId = productId;
}
public Guid ProductId { get; set; }
public Product? Product { get; set; }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
namespace Netina.Domain.Mappers
{
public static partial class ProductMetaTagMapper
{
}
}

View File

@ -100,6 +100,7 @@ public class MapsterRegister : IRegister
config.NewConfig<Order, OrderSDto>() config.NewConfig<Order, OrderSDto>()
.Map("CustomerFullName", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.FirstName + " " + o.Customer.User.LastName : string.Empty) .Map("CustomerFullName", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.FirstName + " " + o.Customer.User.LastName : string.Empty)
.Map("CustomerPhoneNumber", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.PhoneNumber : string.Empty) .Map("CustomerPhoneNumber", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.PhoneNumber : string.Empty)
.Map(d=>d.DeliveryTrackingCode,o=>o.OrderDelivery!=null ? o.OrderDelivery.TrackingCode : string.Empty)
.IgnoreNullValues(false) .IgnoreNullValues(false)
.TwoWays(); .TwoWays();

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<!--<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@ -15,9 +15,9 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.8" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.8" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.8" /> <PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.8" />
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" /> <PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
</ItemGroup>--> </ItemGroup>
<PropertyGroup> <!--<PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<LangVersion>10</LangVersion> <LangVersion>10</LangVersion>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@ -33,7 +33,7 @@
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" /> <PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
</ItemGroup> </ItemGroup>-->
<ItemGroup> <ItemGroup>

View File

@ -81,7 +81,7 @@ public class StorageService(IOptionsSnapshot<SiteSettings> snapshot) : IStorageS
public async Task<List<StorageFileSDto>> GetStorageFiles(StorageFileType fileType) public async Task<List<StorageFileSDto>> GetStorageFiles(StorageFileType fileType)
{ {
var client = GetClientAsync(); var client = GetClientAsync();
ListObjectsRequest request = new() { BucketName = _bucketName}; ListObjectsV2Request request = new() { BucketName = _bucketName, MaxKeys = 3000 };
switch (fileType) switch (fileType)
{ {
case StorageFileType.Image: case StorageFileType.Image:
@ -93,33 +93,22 @@ public class StorageService(IOptionsSnapshot<SiteSettings> snapshot) : IStorageS
default: default:
break; break;
} }
var files = new List<StorageFileSDto>(); var pagination = client.Paginators.ListObjectsV2(request);
do var s3Files = new List<S3Object>();
await foreach (var listObjectsV2Response in pagination.Responses)
{ {
ListObjectsResponse response = await client.ListObjectsAsync(request); s3Files.AddRange(listObjectsV2Response.S3Objects);
}
// Process the response. var files = s3Files
foreach (var s3Object in response.S3Objects.Where(s=>s.Size>0)) .OrderByDescending(s => s.LastModified)
.Take(100)
.Select(s => new StorageFileSDto
{ {
files.Add(new StorageFileSDto FileLocation = s.Key,
{ FileName = s.Key.Split('/').Last()
FileLocation = s3Object.Key, }).ToList();
FileName = s3Object.Key.Split('/').Last()
});
}
// If the response is truncated, set the marker to get the next return files.ToList();
// set of keys.
if (response.IsTruncated)
{
request.Marker = response.NextMarker;
}
else
{
request = null;
}
} while (request != null);
return files.OrderByDescending(o=>o.CreatedAt).ToList();
} }
} }

View File

@ -1,19 +1,35 @@
using Netina.Domain.Entities.Orders; using Netina.Domain.Entities.Orders;
using Netina.Repository.Abstracts;
namespace Netina.Repository.Handlers.Orders; namespace Netina.Repository.Handlers.Orders;
public class GetOrderLDtoQueryHandler(IRepositoryWrapper repositoryWrapper) public class GetOrderLDtoQueryHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService)
: IRequestHandler<GetOrderLDtoQuery, OrderLDto> : IRequestHandler<GetOrderLDtoQuery, OrderLDto>
{ {
public async Task<OrderLDto> Handle(GetOrderLDtoQuery request, CancellationToken cancellationToken) public async Task<OrderLDto> Handle(GetOrderLDtoQuery request, CancellationToken cancellationToken)
{ {
if (currentUserService.Permissions == null)
throw new BaseApiException(ApiResultStatusCode.UnAuthorized);
if (request.Id == default) if (request.Id == default)
throw new AppException("Order id is null"); throw new AppException("Order id is null");
var order = await repositoryWrapper.SetRepository<Order>() var order = await repositoryWrapper.SetRepository<Order>()
.TableNoTracking .TableNoTracking
.Where(o => o.Id == request.Id) .Where(o => o.Id == request.Id)
.Select(OrderMapper.ProjectToLDto) .Select(OrderMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
if (currentUserService.Permissions.Contains(ApplicationPermission.ViewMineOrders) && !currentUserService.Permissions.Contains(ApplicationPermission.ViewAllOrders))
{
if (currentUserService.UserId.IsNullOrEmpty() || !Guid.TryParse(currentUserService.UserId, out Guid userId))
throw new BaseApiException(ApiResultStatusCode.UnAuthorized);
var customer = await repositoryWrapper.SetRepository<Customer>()
.TableNoTracking
.FirstOrDefaultAsync(c => c.UserId == userId, cancellationToken);
if (customer == null || order.CustomerId != customer.Id)
throw new BaseApiException(ApiResultStatusCode.UnAuthorized);
}
if (order == null) if (order == null)
throw new AppException("Order not found", ApiResultStatusCode.NotFound); throw new AppException("Order not found", ApiResultStatusCode.NotFound);
return order; return order;

View File

@ -2,25 +2,25 @@
namespace Netina.Repository.Handlers.Orders; namespace Netina.Repository.Handlers.Orders;
public class GetOrderQueryHandler(IRepositoryWrapper repositoryWrapper) : IRequestHandler<GetOrderQuery, Order> public class GetOrderQueryHandler(IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService) : IRequestHandler<GetOrderQuery, Order>
{ {
public async Task<Order> Handle(GetOrderQuery request, CancellationToken cancellationToken) public async Task<Order> Handle(GetOrderQuery request, CancellationToken cancellationToken)
{ {
var order = await repositoryWrapper.SetRepository<Order>() var order = await repositoryWrapper.SetRepository<Order>()
.TableNoTracking .TableNoTracking
.FirstOrDefaultAsync(o => o.Id == request.Id, cancellationToken); .FirstOrDefaultAsync(o => o.Id == request.Id, cancellationToken);
if (order == null) if (order == null)
throw new AppException("Order not found", ApiResultStatusCode.NotFound); throw new AppException("Order not found", ApiResultStatusCode.NotFound);
var orderProducts = await repositoryWrapper.SetRepository<OrderProduct>() var orderProducts = await repositoryWrapper.SetRepository<OrderProduct>()
.TableNoTracking .TableNoTracking
.Where(op => op.OrderId == order.Id) .Where(op => op.OrderId == order.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
orderProducts.ForEach(op => order.AddOrderProduct(op)); orderProducts.ForEach(op => order.AddOrderProduct(op));
var orderDelivery= await repositoryWrapper.SetRepository<OrderDelivery>() var orderDelivery = await repositoryWrapper.SetRepository<OrderDelivery>()
.TableNoTracking .TableNoTracking
.FirstOrDefaultAsync(od => od.OrderId == request.Id, cancellationToken); .FirstOrDefaultAsync(od => od.OrderId == request.Id, cancellationToken);
if (orderDelivery != null) if (orderDelivery != null)

View File

@ -56,6 +56,9 @@ public class CreateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM
await UpdateFaqAsync(ent, request.Faqs, cancellationToken); await UpdateFaqAsync(ent, request.Faqs, cancellationToken);
foreach (var (key, value) in request.MetaTags)
ent.AddMetaTag(key, value);
return ent.AdaptToLDto(); return ent.AdaptToLDto();
} }

View File

@ -29,6 +29,7 @@ public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM
newEnt.CreatedAt = ent.CreatedAt; newEnt.CreatedAt = ent.CreatedAt;
newEnt.CreatedBy = ent.CreatedBy; newEnt.CreatedBy = ent.CreatedBy;
//Check Specifications
var dbSpecifications = await repositoryWrapper.SetRepository<Specification>().TableNoTracking var dbSpecifications = await repositoryWrapper.SetRepository<Specification>().TableNoTracking
.Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken); .Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken);
foreach (var dbSpecification in dbSpecifications) foreach (var dbSpecification in dbSpecifications)
@ -44,8 +45,22 @@ public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM
newEnt.AddSpecification(specification.Title, specification.Detail, specification.Value, specification.IsFeature, specification.ParentId); newEnt.AddSpecification(specification.Title, specification.Detail, specification.Value, specification.IsFeature, specification.ParentId);
} }
//Check MetaTags
var dbMetaTags = await repositoryWrapper.SetRepository<ProductMetaTag>()
.TableNoTracking
.Where(f => f.ProductId == ent.Id)
.ToListAsync(cancellationToken);
foreach (var feature in dbMetaTags.Where(feature => request.MetaTags.Any(f => f.Key == feature.Type) == false))
{
repositoryWrapper.SetRepository<ProductMetaTag>()
.Delete(feature);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
}
foreach (var (key, value) in request.MetaTags.Where(f => dbMetaTags.Any(dbf => dbf.Type == f.Key) == false))
newEnt.AddMetaTag(key, value);
//Check Files
var dbFiles = await repositoryWrapper.SetRepository<ProductStorageFile>().TableNoTracking var dbFiles = await repositoryWrapper.SetRepository<ProductStorageFile>().TableNoTracking
.Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken); .Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken);
foreach (var dbFile in dbFiles) foreach (var dbFile in dbFiles)

View File

@ -17,7 +17,7 @@ namespace NetinaShop.Repository.Migrations
table: "Products", table: "Products",
type: "uuid", type: "uuid",
nullable: false, nullable: false,
defaultValue: new Guid("8723f1d2-e091-4812-9110-5161c9e23586")); defaultValue: new Guid("11c47231-4f8b-4a73-b848-d2edf3c2d9ab"));
migrationBuilder.AddColumn<Guid>( migrationBuilder.AddColumn<Guid>(
name: "AuthorId", name: "AuthorId",
@ -25,7 +25,7 @@ namespace NetinaShop.Repository.Migrations
table: "Blogs", table: "Blogs",
type: "uuid", type: "uuid",
nullable: false, nullable: false,
defaultValue: new Guid("8723f1d2-e091-4812-9110-5161c9e23586")); defaultValue: new Guid("11c47231-4f8b-4a73-b848-d2edf3c2d9ab"));
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Products_AuthorId", name: "IX_Products_AuthorId",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace NetinaShop.Repository.Migrations
{
/// <inheritdoc />
public partial class AddProductMetaTag : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "ProductId",
schema: "public",
table: "MetaTags",
type: "uuid",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_MetaTags_ProductId",
schema: "public",
table: "MetaTags",
column: "ProductId");
migrationBuilder.AddForeignKey(
name: "FK_MetaTags_Products_ProductId",
schema: "public",
table: "MetaTags",
column: "ProductId",
principalSchema: "public",
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_MetaTags_Products_ProductId",
schema: "public",
table: "MetaTags");
migrationBuilder.DropIndex(
name: "IX_MetaTags_ProductId",
schema: "public",
table: "MetaTags");
migrationBuilder.DropColumn(
name: "ProductId",
schema: "public",
table: "MetaTags");
}
}
}

View File

@ -1698,6 +1698,18 @@ namespace NetinaShop.Repository.Migrations
b.HasDiscriminator().HasValue("ProductCategoryMetaTag"); b.HasDiscriminator().HasValue("ProductCategoryMetaTag");
}); });
modelBuilder.Entity("Netina.Domain.Entities.Products.ProductMetaTag", b =>
{
b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag");
b.Property<Guid>("ProductId")
.HasColumnType("uuid");
b.HasIndex("ProductId");
b.HasDiscriminator().HasValue("ProductMetaTag");
});
modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b =>
{ {
b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile");
@ -2070,6 +2082,16 @@ namespace NetinaShop.Repository.Migrations
b.Navigation("ProductCategory"); b.Navigation("ProductCategory");
}); });
modelBuilder.Entity("Netina.Domain.Entities.Products.ProductMetaTag", b =>
{
b.HasOne("Netina.Domain.Entities.Products.Product", "Product")
.WithMany("MetaTags")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Restrict);
b.Navigation("Product");
});
modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b =>
{ {
b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog") b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog")
@ -2161,6 +2183,8 @@ namespace NetinaShop.Repository.Migrations
b.Navigation("Files"); b.Navigation("Files");
b.Navigation("MetaTags");
b.Navigation("OrderProducts"); b.Navigation("OrderProducts");
b.Navigation("Specifications"); b.Navigation("Specifications");