refactor: update EF Core backing field mapping and ignore DDD enumeration types
This commit is contained in:
@@ -57,7 +57,7 @@ public class OrderController : ControllerBase
|
||||
/// </summary>
|
||||
[HttpPost("pos/orders")]
|
||||
public Task<IActionResult> CreatePosOrder([FromBody] JsonElement body) =>
|
||||
_order.PostAsJsonAsync("/api/v1/pos/orders", body).ProxyAsync();
|
||||
_order.PostAsJsonAsync("/api/v1/orders", body).ProxyAsync();
|
||||
|
||||
/// <summary>
|
||||
/// EN: Get POS dashboard data — daily revenue, order count, popular items.
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Text.Json;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using CatalogService.API.Application.DTOs;
|
||||
using CatalogService.Domain.AggregatesModel.ProductAggregate;
|
||||
using CatalogService.Domain.SeedWork;
|
||||
using CatalogService.Infrastructure;
|
||||
|
||||
namespace CatalogService.API.Application.Queries;
|
||||
@@ -24,27 +26,29 @@ public class GetProductByIdQueryHandler : IRequestHandler<GetProductByIdQuery, P
|
||||
|
||||
public async Task<ProductDto?> Handle(GetProductByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var product = await _context.Products
|
||||
.Where(p => p.Id == request.ProductId)
|
||||
.Select(p => new ProductDto
|
||||
{
|
||||
Id = p.Id,
|
||||
ShopId = p.ShopId,
|
||||
Name = p.Name,
|
||||
Description = p.Description,
|
||||
Price = p.Price,
|
||||
Type = p.Type.Name,
|
||||
Attributes = p.Attributes != null
|
||||
? JsonSerializer.Deserialize<Dictionary<string, object>>(p.Attributes.RootElement.GetRawText())
|
||||
: null,
|
||||
ImageUrl = p.ImageUrl,
|
||||
Sku = p.Sku,
|
||||
IsActive = p.IsActive,
|
||||
CreatedAt = p.CreatedAt,
|
||||
UpdatedAt = p.UpdatedAt
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
var typeMap = Enumeration.GetAll<ProductType>().ToDictionary(t => t.Id, t => t.Name);
|
||||
|
||||
return product;
|
||||
var entity = await _context.Products
|
||||
.FirstOrDefaultAsync(p => p.Id == request.ProductId, cancellationToken);
|
||||
|
||||
if (entity == null) return null;
|
||||
|
||||
return new ProductDto
|
||||
{
|
||||
Id = entity.Id,
|
||||
ShopId = entity.ShopId,
|
||||
Name = entity.Name,
|
||||
Description = entity.Description,
|
||||
Price = entity.Price,
|
||||
Type = typeMap.GetValueOrDefault(entity.TypeId, "Unknown"),
|
||||
Attributes = entity.Attributes != null
|
||||
? JsonSerializer.Deserialize<Dictionary<string, object>>(entity.Attributes.RootElement.GetRawText())
|
||||
: null,
|
||||
ImageUrl = entity.ImageUrl,
|
||||
Sku = entity.Sku,
|
||||
IsActive = entity.IsActive,
|
||||
CreatedAt = entity.CreatedAt,
|
||||
UpdatedAt = entity.UpdatedAt
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Text.Json;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using CatalogService.API.Application.DTOs;
|
||||
using CatalogService.Domain.AggregatesModel.ProductAggregate;
|
||||
using CatalogService.Domain.SeedWork;
|
||||
using CatalogService.Infrastructure;
|
||||
|
||||
namespace CatalogService.API.Application.Queries;
|
||||
@@ -36,24 +38,30 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, PagedRe
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Type))
|
||||
{
|
||||
query = query.Where(p => p.Type.Name == request.Type);
|
||||
// EN: Resolve TypeId from enumeration name for server-side filtering.
|
||||
// VI: Resolve TypeId từ tên enumeration để lọc phía server.
|
||||
var typeEnum = Enumeration.FromDisplayName<ProductType>(request.Type);
|
||||
query = query.Where(p => p.TypeId == typeEnum.Id);
|
||||
}
|
||||
|
||||
// EN: Get total count
|
||||
// VI: Lấy tổng số
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
// EN: Apply pagination and load entities, then project in memory
|
||||
// (JsonDocument cannot be projected server-side by EF Core).
|
||||
// VI: Phân trang và load entities, rồi project trong bộ nhớ
|
||||
// (JsonDocument không thể project server-side bởi EF Core).
|
||||
// EN: Apply pagination and load entities, then project in memory.
|
||||
// Type navigation is ignored by EF Core, so resolve name from Enumeration.
|
||||
// VI: Phân trang và load entities, rồi project trong bộ nhớ.
|
||||
// Type navigation bị ignore bởi EF Core, nên resolve tên từ Enumeration.
|
||||
var entities = await query
|
||||
.Include(p => p.Type)
|
||||
.OrderBy(p => p.Name)
|
||||
.Skip((request.Page - 1) * request.PageSize)
|
||||
.Take(request.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// EN: Build TypeId → Name lookup from Enumeration.
|
||||
// VI: Build lookup TypeId → Name từ Enumeration.
|
||||
var typeMap = Enumeration.GetAll<ProductType>().ToDictionary(t => t.Id, t => t.Name);
|
||||
|
||||
var products = entities.Select(p => new ProductDto
|
||||
{
|
||||
Id = p.Id,
|
||||
@@ -61,7 +69,7 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, PagedRe
|
||||
Name = p.Name,
|
||||
Description = p.Description,
|
||||
Price = p.Price,
|
||||
Type = p.Type?.Name ?? "Unknown",
|
||||
Type = typeMap.GetValueOrDefault(p.TypeId, "Unknown"),
|
||||
Attributes = p.Attributes != null
|
||||
? JsonSerializer.Deserialize<Dictionary<string, object>>(p.Attributes.RootElement.GetRawText())
|
||||
: null,
|
||||
|
||||
@@ -18,7 +18,6 @@ public class Product : Entity, IAggregateRoot
|
||||
private string _name = null!;
|
||||
private string? _description;
|
||||
private decimal _price;
|
||||
private ProductType _type = null!;
|
||||
private JsonDocument? _attributes; // Type-specific attributes in JSONB
|
||||
private string? _imageUrl;
|
||||
private string? _sku;
|
||||
@@ -50,12 +49,6 @@ public class Product : Entity, IAggregateRoot
|
||||
/// </summary>
|
||||
public decimal Price => _price;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Product type.
|
||||
/// VI: Loại sản phẩm.
|
||||
/// </summary>
|
||||
public ProductType Type => _type;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Type ID for EF Core mapping.
|
||||
/// VI: Type ID cho EF Core mapping.
|
||||
@@ -132,7 +125,6 @@ public class Product : Entity, IAggregateRoot
|
||||
_name = name.Trim();
|
||||
_description = description?.Trim();
|
||||
_price = price;
|
||||
_type = type;
|
||||
TypeId = type.Id;
|
||||
_attributes = attributes;
|
||||
_sku = sku?.Trim();
|
||||
|
||||
@@ -53,7 +53,14 @@ public class CatalogContext : DbContext, IUnitOfWork
|
||||
// VI: Áp dụng các cấu hình entity
|
||||
modelBuilder.ApplyConfiguration(new ProductEntityTypeConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new CategoryEntityTypeConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new ProductTypeEntityTypeConfiguration());
|
||||
|
||||
// EN: Ignore ProductType so EF Core does NOT auto-discover Product.TypeId as a FK.
|
||||
// ProductType is a DDD Enumeration resolved in-memory; the product_types table
|
||||
// is seeded by the initial migration and not managed at runtime.
|
||||
// VI: Ignore ProductType để EF Core KHÔNG tự phát hiện Product.TypeId là FK.
|
||||
// ProductType là DDD Enumeration được resolve trong bộ nhớ; bảng product_types
|
||||
// được seed bởi migration khởi tạo và không được quản lý lúc runtime.
|
||||
modelBuilder.Ignore<ProductType>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -98,11 +98,9 @@ public class ProductEntityTypeConfiguration : IEntityTypeConfiguration<Product>
|
||||
builder.HasIndex(p => p.Sku).HasDatabaseName("ix_products_sku");
|
||||
builder.HasIndex(p => p.IsActive).HasDatabaseName("ix_products_is_active");
|
||||
|
||||
// EN: Configure navigation to ProductType via TypeId foreign key.
|
||||
// VI: Cấu hình navigation đến ProductType qua TypeId foreign key.
|
||||
builder.HasOne(p => p.Type)
|
||||
.WithMany()
|
||||
.HasForeignKey(p => p.TypeId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
// EN: TypeId is a plain FK column — no navigation property to ProductType.
|
||||
// Type name is resolved from Enumeration in query handlers.
|
||||
// VI: TypeId là cột FK thuần — không có navigation property đến ProductType.
|
||||
// Tên Type được resolve từ Enumeration trong query handlers.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,14 @@ public class InventoryItemEntityTypeConfiguration : IEntityTypeConfiguration<Inv
|
||||
builder.HasKey(i => i.Id);
|
||||
builder.Property(i => i.Id).HasColumnName("id").ValueGeneratedNever();
|
||||
|
||||
builder.Property<Guid>("_productId").HasColumnName("product_id").IsRequired();
|
||||
builder.Property<Guid>("_shopId").HasColumnName("shop_id").IsRequired();
|
||||
builder.Property<int>("_quantity").HasColumnName("quantity").IsRequired();
|
||||
builder.Property<int>("_reservedQuantity").HasColumnName("reserved_quantity").IsRequired();
|
||||
builder.Property<int>("_reorderLevel").HasColumnName("reorder_level").HasDefaultValue(10);
|
||||
builder.Property<DateTime?>("_updatedAt").HasColumnName("updated_at");
|
||||
builder.Property(i => i.ProductId).HasField("_productId").HasColumnName("product_id").IsRequired();
|
||||
builder.Property(i => i.ShopId).HasField("_shopId").HasColumnName("shop_id").IsRequired();
|
||||
builder.Property(i => i.Quantity).HasField("_quantity").HasColumnName("quantity").IsRequired();
|
||||
builder.Property(i => i.ReservedQuantity).HasField("_reservedQuantity").HasColumnName("reserved_quantity").IsRequired();
|
||||
builder.Property(i => i.ReorderLevel).HasField("_reorderLevel").HasColumnName("reorder_level").HasDefaultValue(10);
|
||||
builder.Property(i => i.UpdatedAt).HasField("_updatedAt").HasColumnName("updated_at");
|
||||
|
||||
builder.Ignore(i => i.CreatedAt);
|
||||
|
||||
// Owned InventoryTransaction collection
|
||||
builder.OwnsMany(i => i.Transactions, txn =>
|
||||
@@ -44,15 +46,11 @@ public class InventoryItemEntityTypeConfiguration : IEntityTypeConfiguration<Inv
|
||||
txn.Ignore(t => t.CreatedAt);
|
||||
});
|
||||
|
||||
builder.HasIndex("_productId").HasDatabaseName("ix_inventory_product_id");
|
||||
builder.HasIndex("_shopId").HasDatabaseName("ix_inventory_shop_id");
|
||||
builder.HasIndex(i => i.ProductId).HasDatabaseName("ix_inventory_product_id");
|
||||
builder.HasIndex(i => i.ShopId).HasDatabaseName("ix_inventory_shop_id");
|
||||
|
||||
builder.Ignore(i => i.ProductId);
|
||||
builder.Ignore(i => i.ShopId);
|
||||
builder.Ignore(i => i.Quantity);
|
||||
builder.Ignore(i => i.ReservedQuantity);
|
||||
// EN: AvailableQuantity is computed (Quantity - ReservedQuantity), not stored.
|
||||
// VI: AvailableQuantity được tính toán (Quantity - ReservedQuantity), không lưu.
|
||||
builder.Ignore(i => i.AvailableQuantity);
|
||||
builder.Ignore(i => i.ReorderLevel);
|
||||
builder.Ignore(i => i.UpdatedAt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,11 @@ public class InventoryContext : DbContext, IUnitOfWork
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.ApplyConfiguration(new InventoryItemEntityTypeConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new TransactionTypeEntityTypeConfiguration());
|
||||
|
||||
// EN: Ignore TransactionType so EF Core does NOT auto-discover TypeId as a FK.
|
||||
// TransactionType is a DDD Enumeration resolved in-memory.
|
||||
// VI: Ignore TransactionType để EF Core KHÔNG tự phát hiện TypeId là FK.
|
||||
modelBuilder.Ignore<TransactionType>();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -95,14 +95,14 @@ public class InventoryRepository : IInventoryRepository
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = _context.InventoryItems
|
||||
.Where(i => i.AvailableQuantity <= i.ReorderLevel);
|
||||
.Where(i => (i.Quantity - i.ReservedQuantity) <= i.ReorderLevel);
|
||||
|
||||
if (shopId.HasValue)
|
||||
query = query.Where(i => i.ShopId == shopId.Value);
|
||||
|
||||
var total = await query.CountAsync(cancellationToken);
|
||||
var items = await query
|
||||
.OrderBy(i => i.AvailableQuantity)
|
||||
.OrderBy(i => i.Quantity - i.ReservedQuantity)
|
||||
.Skip(skip)
|
||||
.Take(take)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
@@ -23,14 +23,17 @@ public class MerchantStaffEntityTypeConfiguration : IEntityTypeConfiguration<Mer
|
||||
.HasColumnName("id")
|
||||
.ValueGeneratedNever();
|
||||
|
||||
builder.Property<Guid>("_userId")
|
||||
builder.Property(s => s.UserId)
|
||||
.HasField("_userId")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
builder.Property<Guid>("_merchantId")
|
||||
builder.Property(s => s.MerchantId)
|
||||
.HasField("_merchantId")
|
||||
.HasColumnName("merchant_id")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<string?>("_employeeCode")
|
||||
builder.Property(s => s.EmployeeCode)
|
||||
.HasField("_employeeCode")
|
||||
.HasColumnName("employee_code")
|
||||
.HasMaxLength(20);
|
||||
|
||||
@@ -42,33 +45,41 @@ public class MerchantStaffEntityTypeConfiguration : IEntityTypeConfiguration<Mer
|
||||
.HasColumnName("status_id")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<StaffPermissions>("_permissions")
|
||||
builder.Property(s => s.Permissions)
|
||||
.HasField("_permissions")
|
||||
.HasColumnName("permissions")
|
||||
.HasConversion<int>();
|
||||
|
||||
builder.Property<string?>("_phone")
|
||||
builder.Property(s => s.Phone)
|
||||
.HasField("_phone")
|
||||
.HasColumnName("phone")
|
||||
.HasMaxLength(20);
|
||||
|
||||
builder.Property<string?>("_email")
|
||||
builder.Property(s => s.Email)
|
||||
.HasField("_email")
|
||||
.HasColumnName("email")
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property<string?>("_pinCodeHash")
|
||||
builder.Property(s => s.PinCodeHash)
|
||||
.HasField("_pinCodeHash")
|
||||
.HasColumnName("pin_code_hash")
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property<DateTime>("_joinedAt")
|
||||
builder.Property(s => s.JoinedAt)
|
||||
.HasField("_joinedAt")
|
||||
.HasColumnName("joined_at");
|
||||
|
||||
builder.Property<DateTime?>("_terminatedAt")
|
||||
builder.Property(s => s.TerminatedAt)
|
||||
.HasField("_terminatedAt")
|
||||
.HasColumnName("terminated_at");
|
||||
|
||||
builder.Property<DateTime>("_createdAt")
|
||||
builder.Property(s => s.CreatedAt)
|
||||
.HasField("_createdAt")
|
||||
.HasColumnName("created_at")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<DateTime?>("_updatedAt")
|
||||
builder.Property(s => s.UpdatedAt)
|
||||
.HasField("_updatedAt")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
// EN: Configure navigation to device tokens
|
||||
@@ -87,26 +98,14 @@ public class MerchantStaffEntityTypeConfiguration : IEntityTypeConfiguration<Mer
|
||||
|
||||
// EN: Indexes
|
||||
// VI: Indexes
|
||||
builder.HasIndex("_userId").HasDatabaseName("ix_merchant_staff_user_id");
|
||||
builder.HasIndex("_merchantId").HasDatabaseName("ix_merchant_staff_merchant_id");
|
||||
builder.HasIndex("_email").HasDatabaseName("ix_merchant_staff_email");
|
||||
builder.HasIndex(s => s.UserId).HasDatabaseName("ix_merchant_staff_user_id");
|
||||
builder.HasIndex(s => s.MerchantId).HasDatabaseName("ix_merchant_staff_merchant_id");
|
||||
builder.HasIndex(s => s.Email).HasDatabaseName("ix_merchant_staff_email");
|
||||
|
||||
// EN: Ignore expression-bodied properties (EF Core can't map them)
|
||||
// EN: Repository queries use EF.Property<T>() to access backing fields directly.
|
||||
// VI: Ignore expression-bodied properties (EF Core không thể map chúng)
|
||||
// EN: Ignore Enumeration navigation properties (resolved in-memory).
|
||||
// VI: Ignore Enumeration navigation properties (resolve trong bộ nhớ).
|
||||
builder.Ignore(s => s.Role);
|
||||
builder.Ignore(s => s.Status);
|
||||
builder.Ignore(s => s.Permissions);
|
||||
builder.Ignore(s => s.UserId);
|
||||
builder.Ignore(s => s.MerchantId);
|
||||
builder.Ignore(s => s.EmployeeCode);
|
||||
builder.Ignore(s => s.Phone);
|
||||
builder.Ignore(s => s.Email);
|
||||
builder.Ignore(s => s.PinCodeHash);
|
||||
builder.Ignore(s => s.JoinedAt);
|
||||
builder.Ignore(s => s.TerminatedAt);
|
||||
builder.Ignore(s => s.CreatedAt);
|
||||
builder.Ignore(s => s.UpdatedAt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,44 +129,41 @@ public class DeviceTokenEntityTypeConfiguration : IEntityTypeConfiguration<Devic
|
||||
.HasColumnName("staff_id")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<string>("_deviceId")
|
||||
builder.Property(d => d.DeviceId)
|
||||
.HasField("_deviceId")
|
||||
.HasColumnName("device_id")
|
||||
.HasMaxLength(100)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<string?>("_deviceName")
|
||||
builder.Property(d => d.DeviceName)
|
||||
.HasField("_deviceName")
|
||||
.HasColumnName("device_name")
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property<string?>("_fcmToken")
|
||||
builder.Property(d => d.FcmToken)
|
||||
.HasField("_fcmToken")
|
||||
.HasColumnName("fcm_token")
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property<string>("_platform")
|
||||
builder.Property(d => d.Platform)
|
||||
.HasField("_platform")
|
||||
.HasColumnName("platform")
|
||||
.HasMaxLength(20)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<DateTime?>("_lastUsedAt")
|
||||
builder.Property(d => d.LastUsedAt)
|
||||
.HasField("_lastUsedAt")
|
||||
.HasColumnName("last_used_at");
|
||||
|
||||
builder.Property<DateTime>("_createdAt")
|
||||
builder.Property(d => d.CreatedAt)
|
||||
.HasField("_createdAt")
|
||||
.HasColumnName("created_at")
|
||||
.IsRequired();
|
||||
|
||||
// EN: Indexes
|
||||
// VI: Indexes
|
||||
builder.HasIndex(d => d.StaffId).HasDatabaseName("ix_device_tokens_staff_id");
|
||||
builder.HasIndex("_deviceId").HasDatabaseName("ix_device_tokens_device_id");
|
||||
|
||||
// EN: Ignore expression-bodied properties
|
||||
// VI: Ignore expression-bodied properties
|
||||
builder.Ignore(d => d.DeviceId);
|
||||
builder.Ignore(d => d.DeviceName);
|
||||
builder.Ignore(d => d.FcmToken);
|
||||
builder.Ignore(d => d.Platform);
|
||||
builder.Ignore(d => d.LastUsedAt);
|
||||
builder.Ignore(d => d.CreatedAt);
|
||||
builder.HasIndex(d => d.DeviceId).HasDatabaseName("ix_device_tokens_device_id");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,42 +187,42 @@ public class ShopMemberEntityTypeConfiguration : IEntityTypeConfiguration<ShopMe
|
||||
.HasColumnName("staff_id")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<Guid>("_shopId")
|
||||
builder.Property(m => m.ShopId)
|
||||
.HasField("_shopId")
|
||||
.HasColumnName("shop_id")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<Guid?>("_branchId")
|
||||
builder.Property(m => m.BranchId)
|
||||
.HasField("_branchId")
|
||||
.HasColumnName("branch_id");
|
||||
|
||||
builder.Property(m => m.RoleId)
|
||||
.HasColumnName("role_id")
|
||||
.IsRequired();
|
||||
|
||||
builder.Property<StaffPermissions?>("_customPermissions")
|
||||
builder.Property(m => m.CustomPermissions)
|
||||
.HasField("_customPermissions")
|
||||
.HasColumnName("custom_permissions")
|
||||
.HasConversion<int?>();
|
||||
|
||||
builder.Property<bool>("_isPrimary")
|
||||
builder.Property(m => m.IsPrimary)
|
||||
.HasField("_isPrimary")
|
||||
.HasColumnName("is_primary")
|
||||
.HasDefaultValue(false);
|
||||
|
||||
builder.Property<DateTime>("_assignedAt")
|
||||
builder.Property(m => m.AssignedAt)
|
||||
.HasField("_assignedAt")
|
||||
.HasColumnName("assigned_at")
|
||||
.IsRequired();
|
||||
|
||||
// EN: Indexes
|
||||
// VI: Indexes
|
||||
builder.HasIndex(m => m.StaffId).HasDatabaseName("ix_shop_members_staff_id");
|
||||
builder.HasIndex("_shopId").HasDatabaseName("ix_shop_members_shop_id");
|
||||
builder.HasIndex(m => m.ShopId).HasDatabaseName("ix_shop_members_shop_id");
|
||||
|
||||
// EN: Ignore expression-bodied properties
|
||||
// VI: Ignore expression-bodied properties
|
||||
// EN: Ignore Enumeration navigation property (resolved in-memory).
|
||||
// VI: Ignore Enumeration navigation property (resolve trong bộ nhớ).
|
||||
builder.Ignore(m => m.Role);
|
||||
builder.Ignore(m => m.CustomPermissions);
|
||||
builder.Ignore(m => m.ShopId);
|
||||
builder.Ignore(m => m.BranchId);
|
||||
builder.Ignore(m => m.IsPrimary);
|
||||
builder.Ignore(m => m.AssignedAt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,13 @@ public class MerchantServiceContext : DbContext, IUnitOfWork
|
||||
// EN: Apply entity configurations from this assembly
|
||||
// VI: Áp dụng các cấu hình entity từ assembly này
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(typeof(MerchantServiceContext).Assembly);
|
||||
|
||||
// EN: Ignore Enumeration types so EF Core does NOT auto-discover FKs.
|
||||
// These are DDD Enumerations resolved in-memory; their tables are seeded by migrations.
|
||||
// VI: Ignore Enumeration types để EF Core KHÔNG tự phát hiện FK.
|
||||
modelBuilder.Ignore<StaffRole>();
|
||||
modelBuilder.Ignore<StaffStatus>();
|
||||
modelBuilder.Ignore<ShopRole>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user