From c9fdb56cb8b0412fd52cd8c9300f50778fb614c1 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Sun, 18 Jan 2026 00:36:53 +0700 Subject: [PATCH] feat: Remove sample aggregates, introduce BillingAccount aggregate, and refactor CatalogServiceContext to CatalogContext. --- .../BillingAccountAggregate/BillingAccount.cs | 146 ++++++++++++++++ .../SampleAggregate/ISampleRepository.cs | 61 ------- .../AggregatesModel/SampleAggregate/Sample.cs | 158 ------------------ .../SampleAggregate/SampleStatus.cs | 77 --------- .../Controllers/AdsController.cs | 4 +- .../Behaviors/TransactionBehavior.cs | 4 +- .../CatalogService.API.csproj | 4 + .../CatalogContext.cs | 5 - .../DependencyInjection.cs | 8 +- .../SampleEntityTypeConfiguration.cs | 61 ------- .../SampleStatusEntityTypeConfiguration.cs | 39 ----- .../Idempotency/RequestManager.cs | 4 +- .../Repositories/SampleRepository.cs | 72 -------- .../CustomWebApplicationFactory.cs | 8 +- 14 files changed, 164 insertions(+), 487 deletions(-) create mode 100644 services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/BillingAccountAggregate/BillingAccount.cs delete mode 100644 services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs delete mode 100644 services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/Sample.cs delete mode 100644 services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs delete mode 100644 services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs delete mode 100644 services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs delete mode 100644 services/catalog-service-net/src/CatalogService.Infrastructure/Repositories/SampleRepository.cs diff --git a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/BillingAccountAggregate/BillingAccount.cs b/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/BillingAccountAggregate/BillingAccount.cs new file mode 100644 index 00000000..cb3e551a --- /dev/null +++ b/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/BillingAccountAggregate/BillingAccount.cs @@ -0,0 +1,146 @@ +using AdsBillingService.Domain.SeedWork; + +namespace AdsBillingService.Domain.AggregatesModel.BillingAccountAggregate; + +/// +/// EN: Billing account aggregate root - manages advertiser billing and payments. +/// VI: Billing account aggregate root - quản lý thanh toán và billing của advertiser. +/// +public class BillingAccount : Entity, IAggregateRoot +{ + private Guid _advertiserId; + private Guid? _walletId; + private PaymentMethodType _paymentMethod; + private BillingThreshold? _threshold; + private AccountStatus _status; + private decimal _balance; + private decimal _creditLimit; + + public Guid AdvertiserId => _advertiserId; + public Guid? WalletId => _walletId; + public PaymentMethodType PaymentMethod => _paymentMethod; + public BillingThreshold? Threshold => _threshold; + public AccountStatus Status => _status; + public decimal Balance => _balance; + public decimal CreditLimit => _creditLimit; + public DateTime CreatedAt { get; private set; } + public DateTime? UpdatedAt { get; private set; } + + protected BillingAccount() { } + + public BillingAccount(Guid advertiserId, Guid? walletId, PaymentMethodType paymentMethod) + { + Id = Guid.NewGuid(); + _advertiserId = advertiserId; + _walletId = walletId; + _paymentMethod = paymentMethod; + _status = AccountStatus.Active; + _balance = 0; + _creditLimit = 0; + CreatedAt = DateTime.UtcNow; + } + + /// + /// EN: Set auto-charge threshold for prepaid accounts. + /// VI: Thiết lập ngưỡng tự động nạp tiền cho tài khoản trả trước. + /// + public void SetThreshold(decimal amount, bool autoCharge) + { + _threshold = new BillingThreshold(amount, autoCharge); + _UpdatedAt = DateTime.UtcNow; + } + + /// + /// EN: Deduct amount from balance (for prepaid). + /// VI: Trừ tiền từ số dư (cho trả trước). + /// + public void DeductBalance(decimal amount) + { + if (_paymentMethod != PaymentMethodType.Prepaid) + throw new AdsBillingDomainException("Can only deduct from prepaid accounts"); + + if (_balance < amount) + throw new AdsBillingDomainException("Insufficient balance"); + + _balance -= amount; + _UpdatedAt = DateTime.UtcNow; + } + + /// + /// EN: Add balance (from wallet top-up). + /// VI: Thêm số dư (từ nạp ví). + /// + public void AddBalance(decimal amount) + { + if (amount <= 0) + throw new AdsBillingDomainException("Amount must be positive"); + + _balance += amount; + _UpdatedAt = DateTime.UtcNow; + } + + /// + /// EN: Suspend account (e.g., due to payment issues). + /// VI: Tạm ngưng tài khoản (ví dụ do vấn đề thanh toán). + /// + public void Suspend() + { + _status = AccountStatus.Suspended; + _UpdatedAt = DateTime.UtcNow; + } + + private DateTime? _UpdatedAt + { + get => UpdatedAt; + set => UpdatedAt = value; + } +} + +/// +/// EN: Payment method type enumeration. +/// VI: Enum loại phương thức thanh toán. +/// +public enum PaymentMethodType +{ + Prepaid = 1, // Pay upfront via Wallet + Postpaid = 2, // Monthly invoice + CreditCard = 3 // Auto-charge credit card +} + +/// +/// EN: Account status enumeration. +/// VI: Enum trạng thái tài khoản. +/// +public enum AccountStatus +{ + Active = 1, + Suspended = 2, + Closed = 3 +} + +/// +/// EN: Billing threshold value object. +/// VI: Value object ngưỡng billing. +/// +public class BillingThreshold : ValueObject +{ + public decimal Amount { get; private set; } + public bool AutoCharge { get; private set; } + + protected BillingThreshold() { } + + public BillingThreshold(decimal amount, bool autoCharge) + { + if (amount <= 0) + throw new AdsBillingDomainException("Threshold amount must be positive"); + + Amount = amount; + AutoCharge = autoCharge; + } + + protected override IEnumerable GetEqualityComponents() + { + yield return Amount; + yield return AutoCharge; + } +} diff --git a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs b/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs deleted file mode 100644 index 20369fb9..00000000 --- a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs +++ /dev/null @@ -1,61 +0,0 @@ -using AdsBillingService.Domain.SeedWork; - -namespace AdsBillingService.Domain.AggregatesModel.SampleAggregate; - -/// -/// EN: Repository interface for Sample aggregate. -/// VI: Interface repository cho Sample aggregate. -/// -/// -/// EN: Following repository pattern, this interface defines the contract -/// for data access operations on Sample aggregate. -/// VI: Theo pattern repository, interface này định nghĩa contract -/// cho các thao tác truy cập dữ liệu trên Sample aggregate. -/// -public interface ISampleRepository : IRepository -{ - /// - /// EN: Get a sample by its ID. - /// VI: Lấy một sample theo ID. - /// - /// EN: The sample ID / VI: ID của sample - /// EN: The sample or null if not found / VI: Sample hoặc null nếu không tìm thấy - Task GetAsync(Guid sampleId); - - /// - /// EN: Get all samples. - /// VI: Lấy tất cả samples. - /// - /// EN: List of samples / VI: Danh sách samples - Task> GetAllAsync(); - - /// - /// EN: Add a new sample. - /// VI: Thêm một sample mới. - /// - /// EN: The sample to add / VI: Sample cần thêm - /// EN: The added sample / VI: Sample đã thêm - Sample Add(Sample sample); - - /// - /// EN: Update an existing sample. - /// VI: Cập nhật một sample đã tồn tại. - /// - /// EN: The sample to update / VI: Sample cần cập nhật - void Update(Sample sample); - - /// - /// EN: Delete a sample. - /// VI: Xóa một sample. - /// - /// EN: The sample to delete / VI: Sample cần xóa - void Delete(Sample sample); - - /// - /// EN: Get samples by status. - /// VI: Lấy samples theo trạng thái. - /// - /// EN: The status ID / VI: ID trạng thái - /// EN: List of samples with given status / VI: Danh sách samples với trạng thái cho trước - Task> GetByStatusAsync(int statusId); -} diff --git a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/Sample.cs b/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/Sample.cs deleted file mode 100644 index f282a68d..00000000 --- a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/Sample.cs +++ /dev/null @@ -1,158 +0,0 @@ -using AdsBillingService.Domain.Events; -using AdsBillingService.Domain.Exceptions; -using AdsBillingService.Domain.SeedWork; - -namespace AdsBillingService.Domain.AggregatesModel.SampleAggregate; - -/// -/// EN: Sample aggregate root demonstrating DDD patterns. -/// VI: Sample aggregate root minh họa các pattern DDD. -/// -public class Sample : Entity, IAggregateRoot -{ - // EN: Private fields for encapsulation - // VI: Fields private để đóng gói - private string _name = null!; - private string? _description; - private SampleStatus _status = null!; - private DateTime _createdAt; - private DateTime? _updatedAt; - - /// - /// EN: Sample name (required). - /// VI: Tên sample (bắt buộc). - /// - public string Name => _name; - - /// - /// EN: Optional description. - /// VI: Mô tả tùy chọn. - /// - public string? Description => _description; - - /// - /// EN: Current status. - /// VI: Trạng thái hiện tại. - /// - public SampleStatus Status => _status; - - /// - /// EN: Status ID for EF Core mapping. - /// VI: ID trạng thái cho EF Core mapping. - /// - public int StatusId { get; private set; } - - /// - /// EN: Creation timestamp. - /// VI: Thời gian tạo. - /// - public DateTime CreatedAt => _createdAt; - - /// - /// EN: Last update timestamp. - /// VI: Thời gian cập nhật cuối. - /// - public DateTime? UpdatedAt => _updatedAt; - - /// - /// EN: Private constructor for EF Core. - /// VI: Constructor private cho EF Core. - /// - protected Sample() - { - } - - /// - /// EN: Create a new Sample with required information. - /// VI: Tạo một Sample mới với thông tin bắt buộc. - /// - /// EN: Sample name / VI: Tên sample - /// EN: Optional description / VI: Mô tả tùy chọn - public Sample(string name, string? description = null) : this() - { - if (string.IsNullOrWhiteSpace(name)) - throw new SampleDomainException("Sample name cannot be empty"); - - Id = Guid.NewGuid(); - _name = name; - _description = description; - _status = SampleStatus.Draft; - StatusId = SampleStatus.Draft.Id; - _createdAt = DateTime.UtcNow; - - // EN: Add domain event for creation - // VI: Thêm domain event cho việc tạo - AddDomainEvent(new SampleCreatedDomainEvent(this)); - } - - /// - /// EN: Update sample information. - /// VI: Cập nhật thông tin sample. - /// - public void Update(string name, string? description) - { - if (string.IsNullOrWhiteSpace(name)) - throw new SampleDomainException("Sample name cannot be empty"); - - if (_status == SampleStatus.Cancelled) - throw new SampleDomainException("Cannot update a cancelled sample"); - - _name = name; - _description = description; - _updatedAt = DateTime.UtcNow; - } - - /// - /// EN: Activate the sample. - /// VI: Kích hoạt sample. - /// - public void Activate() - { - if (_status != SampleStatus.Draft) - throw new SampleDomainException("Only draft samples can be activated"); - - var previousStatus = _status; - _status = SampleStatus.Active; - StatusId = SampleStatus.Active.Id; - _updatedAt = DateTime.UtcNow; - - AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status)); - } - - /// - /// EN: Complete the sample. - /// VI: Hoàn thành sample. - /// - public void Complete() - { - if (_status != SampleStatus.Active) - throw new SampleDomainException("Only active samples can be completed"); - - var previousStatus = _status; - _status = SampleStatus.Completed; - StatusId = SampleStatus.Completed.Id; - _updatedAt = DateTime.UtcNow; - - AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status)); - } - - /// - /// EN: Cancel the sample. - /// VI: Hủy sample. - /// - public void Cancel() - { - if (_status == SampleStatus.Completed) - throw new SampleDomainException("Cannot cancel a completed sample"); - - if (_status == SampleStatus.Cancelled) - throw new SampleDomainException("Sample is already cancelled"); - - var previousStatus = _status; - _status = SampleStatus.Cancelled; - StatusId = SampleStatus.Cancelled.Id; - _updatedAt = DateTime.UtcNow; - - AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status)); - } -} diff --git a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs b/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs deleted file mode 100644 index ac42c55f..00000000 --- a/services/ads-billing-service-net/src/AdsBillingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs +++ /dev/null @@ -1,77 +0,0 @@ -using AdsBillingService.Domain.SeedWork; - -namespace AdsBillingService.Domain.AggregatesModel.SampleAggregate; - -/// -/// EN: Sample status enumeration following type-safe enum pattern. -/// VI: Enumeration trạng thái Sample theo pattern enum an toàn kiểu. -/// -public class SampleStatus : Enumeration -{ - /// - /// EN: Draft status - initial state - /// VI: Trạng thái nháp - trạng thái ban đầu - /// - public static SampleStatus Draft = new(1, nameof(Draft)); - - /// - /// EN: Active status - ready for use - /// VI: Trạng thái hoạt động - sẵn sàng sử dụng - /// - public static SampleStatus Active = new(2, nameof(Active)); - - /// - /// EN: Completed status - finished processing - /// VI: Trạng thái hoàn thành - đã xử lý xong - /// - public static SampleStatus Completed = new(3, nameof(Completed)); - - /// - /// EN: Cancelled status - cancelled by user - /// VI: Trạng thái đã hủy - bị hủy bởi người dùng - /// - public static SampleStatus Cancelled = new(4, nameof(Cancelled)); - - public SampleStatus(int id, string name) : base(id, name) - { - } - - /// - /// EN: Get all available statuses. - /// VI: Lấy tất cả các trạng thái có sẵn. - /// - public static IEnumerable List() => GetAll(); - - /// - /// EN: Parse status from name. - /// VI: Parse trạng thái từ tên. - /// - public static SampleStatus FromName(string name) - { - var status = List().SingleOrDefault(s => - string.Equals(s.Name, name, StringComparison.CurrentCultureIgnoreCase)); - - if (status is null) - { - throw new ArgumentException($"Possible values for SampleStatus: {string.Join(",", List().Select(s => s.Name))}"); - } - - return status; - } - - /// - /// EN: Parse status from ID. - /// VI: Parse trạng thái từ ID. - /// - public static SampleStatus From(int id) - { - var status = List().SingleOrDefault(s => s.Id == id); - - if (status is null) - { - throw new ArgumentException($"Possible values for SampleStatus: {string.Join(",", List().Select(s => s.Name))}"); - } - - return status; - } -} diff --git a/services/ads-serving-service-net/src/AdsServingService.API/Controllers/AdsController.cs b/services/ads-serving-service-net/src/AdsServingService.API/Controllers/AdsController.cs index 0bcd4702..2fb2bc31 100644 --- a/services/ads-serving-service-net/src/AdsServingService.API/Controllers/AdsController.cs +++ b/services/ads-serving-service-net/src/AdsServingService.API/Controllers/AdsController.cs @@ -23,8 +23,8 @@ public class AdsController : ControllerBase } /// - /// EN: Serve an ad based on user context (< 100ms target). - /// VI: Serve quảng cáo dựa trên ngữ cảnh người dùng (mục tiêu < 100ms). + /// EN: Serve an ad based on user context (less than 100ms target). + /// VI: Serve quảng cáo dựa trên ngữ cảnh người dùng (mục tiêu dưới 100ms). /// [HttpPost("serve")] [ProducesResponseType(typeof(ServedAdDto), StatusCodes.Status200OK)] diff --git a/services/catalog-service-net/src/CatalogService.API/Application/Behaviors/TransactionBehavior.cs b/services/catalog-service-net/src/CatalogService.API/Application/Behaviors/TransactionBehavior.cs index dea12f05..3b708fed 100644 --- a/services/catalog-service-net/src/CatalogService.API/Application/Behaviors/TransactionBehavior.cs +++ b/services/catalog-service-net/src/CatalogService.API/Application/Behaviors/TransactionBehavior.cs @@ -13,11 +13,11 @@ namespace CatalogService.API.Application.Behaviors; public class TransactionBehavior : IPipelineBehavior where TRequest : IRequest { - private readonly CatalogServiceContext _dbContext; + private readonly CatalogContext _dbContext; private readonly ILogger> _logger; public TransactionBehavior( - CatalogServiceContext dbContext, + CatalogContext dbContext, ILogger> logger) { _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); diff --git a/services/catalog-service-net/src/CatalogService.API/CatalogService.API.csproj b/services/catalog-service-net/src/CatalogService.API/CatalogService.API.csproj index 6cbf3bbb..6cea7eab 100644 --- a/services/catalog-service-net/src/CatalogService.API/CatalogService.API.csproj +++ b/services/catalog-service-net/src/CatalogService.API/CatalogService.API.csproj @@ -14,6 +14,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/services/catalog-service-net/src/CatalogService.Infrastructure/CatalogContext.cs b/services/catalog-service-net/src/CatalogService.Infrastructure/CatalogContext.cs index 3c7118ac..04ee6251 100644 --- a/services/catalog-service-net/src/CatalogService.Infrastructure/CatalogContext.cs +++ b/services/catalog-service-net/src/CatalogService.Infrastructure/CatalogContext.cs @@ -40,11 +40,6 @@ public class CatalogContext : DbContext, IUnitOfWork /// public bool HasActiveTransaction => _currentTransaction != null; - public CatalogContext(DbContextOptions options) : base(options) - { - _mediator = null!; - } - public CatalogContext(DbContextOptions options, IMediator mediator) : base(options) { _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); diff --git a/services/catalog-service-net/src/CatalogService.Infrastructure/DependencyInjection.cs b/services/catalog-service-net/src/CatalogService.Infrastructure/DependencyInjection.cs index e39b860d..9390a651 100644 --- a/services/catalog-service-net/src/CatalogService.Infrastructure/DependencyInjection.cs +++ b/services/catalog-service-net/src/CatalogService.Infrastructure/DependencyInjection.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using CatalogService.Domain.AggregatesModel.SampleAggregate; +using CatalogService.Domain.AggregatesModel.ProductAggregate; using CatalogService.Infrastructure.Idempotency; using CatalogService.Infrastructure.Repositories; @@ -22,7 +22,7 @@ public static class DependencyInjection IConfiguration configuration) { // EN: Add DbContext with PostgreSQL / VI: Thêm DbContext với PostgreSQL - services.AddDbContext(options => + services.AddDbContext(options => { var connectionString = configuration.GetConnectionString("DefaultConnection") ?? configuration["DATABASE_URL"] @@ -30,7 +30,7 @@ public static class DependencyInjection options.UseNpgsql(connectionString, npgsqlOptions => { - npgsqlOptions.MigrationsAssembly(typeof(CatalogServiceContext).Assembly.FullName); + npgsqlOptions.MigrationsAssembly(typeof(CatalogContext).Assembly.FullName); npgsqlOptions.EnableRetryOnFailure( maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), @@ -47,7 +47,7 @@ public static class DependencyInjection }); // EN: Register repositories / VI: Đăng ký repositories - services.AddScoped(); + services.AddScoped(); // EN: Register idempotency services / VI: Đăng ký idempotency services services.AddScoped(); diff --git a/services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs b/services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs deleted file mode 100644 index 68ea385b..00000000 --- a/services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using CatalogService.Domain.AggregatesModel.SampleAggregate; - -namespace CatalogService.Infrastructure.EntityConfigurations; - -/// -/// EN: EF Core configuration for Sample entity. -/// VI: Cấu hình EF Core cho entity Sample. -/// -public class SampleEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - // EN: Table name / VI: Tên bảng - builder.ToTable("samples"); - - // EN: Primary key / VI: Khóa chính - builder.HasKey(s => s.Id); - - // EN: Ignore domain events (not persisted) - // VI: Bỏ qua domain events (không lưu) - builder.Ignore(s => s.DomainEvents); - - // EN: Properties / VI: Các thuộc tính - builder.Property(s => s.Id) - .HasColumnName("id") - .IsRequired(); - - builder.Property("_name") - .HasColumnName("name") - .HasMaxLength(200) - .IsRequired(); - - builder.Property("_description") - .HasColumnName("description") - .HasMaxLength(1000); - - builder.Property("_createdAt") - .HasColumnName("created_at") - .IsRequired(); - - builder.Property("_updatedAt") - .HasColumnName("updated_at"); - - // EN: Status relationship / VI: Quan hệ với Status - builder.Property(s => s.StatusId) - .HasColumnName("status_id") - .IsRequired(); - - builder.HasOne(s => s.Status) - .WithMany() - .HasForeignKey(s => s.StatusId) - .OnDelete(DeleteBehavior.Restrict); - - // EN: Indexes / VI: Các index - builder.HasIndex("_name"); - builder.HasIndex(s => s.StatusId); - builder.HasIndex("_createdAt"); - } -} diff --git a/services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs b/services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs deleted file mode 100644 index a057e4f1..00000000 --- a/services/catalog-service-net/src/CatalogService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using CatalogService.Domain.AggregatesModel.SampleAggregate; - -namespace CatalogService.Infrastructure.EntityConfigurations; - -/// -/// EN: EF Core configuration for SampleStatus enumeration. -/// VI: Cấu hình EF Core cho enumeration SampleStatus. -/// -public class SampleStatusEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - // EN: Table name / VI: Tên bảng - builder.ToTable("sample_statuses"); - - // EN: Primary key / VI: Khóa chính - builder.HasKey(s => s.Id); - - builder.Property(s => s.Id) - .HasColumnName("id") - .ValueGeneratedNever() - .IsRequired(); - - builder.Property(s => s.Name) - .HasColumnName("name") - .HasMaxLength(50) - .IsRequired(); - - // EN: Seed initial data / VI: Seed dữ liệu ban đầu - builder.HasData( - SampleStatus.Draft, - SampleStatus.Active, - SampleStatus.Completed, - SampleStatus.Cancelled - ); - } -} diff --git a/services/catalog-service-net/src/CatalogService.Infrastructure/Idempotency/RequestManager.cs b/services/catalog-service-net/src/CatalogService.Infrastructure/Idempotency/RequestManager.cs index 93126bdd..8bdcae84 100644 --- a/services/catalog-service-net/src/CatalogService.Infrastructure/Idempotency/RequestManager.cs +++ b/services/catalog-service-net/src/CatalogService.Infrastructure/Idempotency/RequestManager.cs @@ -8,9 +8,9 @@ namespace CatalogService.Infrastructure.Idempotency; /// public class RequestManager : IRequestManager { - private readonly CatalogServiceContext _context; + private readonly CatalogContext _context; - public RequestManager(CatalogServiceContext context) + public RequestManager(CatalogContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); } diff --git a/services/catalog-service-net/src/CatalogService.Infrastructure/Repositories/SampleRepository.cs b/services/catalog-service-net/src/CatalogService.Infrastructure/Repositories/SampleRepository.cs deleted file mode 100644 index 872662b5..00000000 --- a/services/catalog-service-net/src/CatalogService.Infrastructure/Repositories/SampleRepository.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using CatalogService.Domain.AggregatesModel.SampleAggregate; -using CatalogService.Domain.SeedWork; - -namespace CatalogService.Infrastructure.Repositories; - -/// -/// EN: Repository implementation for Sample aggregate. -/// VI: Triển khai repository cho Sample aggregate. -/// -public class SampleRepository : ISampleRepository -{ - private readonly CatalogServiceContext _context; - - /// - /// EN: Unit of work for transaction management. - /// VI: Unit of work cho quản lý transaction. - /// - public IUnitOfWork UnitOfWork => _context; - - public SampleRepository(CatalogServiceContext context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - } - - /// - public async Task GetAsync(Guid sampleId) - { - var sample = await _context.Samples - .Include(s => s.Status) - .FirstOrDefaultAsync(s => s.Id == sampleId); - - return sample; - } - - /// - public async Task> GetAllAsync() - { - return await _context.Samples - .Include(s => s.Status) - .OrderByDescending(s => s.CreatedAt) - .ToListAsync(); - } - - /// - public Sample Add(Sample sample) - { - return _context.Samples.Add(sample).Entity; - } - - /// - public void Update(Sample sample) - { - _context.Entry(sample).State = EntityState.Modified; - } - - /// - public void Delete(Sample sample) - { - _context.Samples.Remove(sample); - } - - /// - public async Task> GetByStatusAsync(int statusId) - { - return await _context.Samples - .Include(s => s.Status) - .Where(s => s.StatusId == statusId) - .OrderByDescending(s => s.CreatedAt) - .ToListAsync(); - } -} diff --git a/services/catalog-service-net/tests/CatalogService.FunctionalTests/CustomWebApplicationFactory.cs b/services/catalog-service-net/tests/CatalogService.FunctionalTests/CustomWebApplicationFactory.cs index 2d01c732..8aa02cfe 100644 --- a/services/catalog-service-net/tests/CatalogService.FunctionalTests/CustomWebApplicationFactory.cs +++ b/services/catalog-service-net/tests/CatalogService.FunctionalTests/CustomWebApplicationFactory.cs @@ -21,7 +21,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory // EN: Remove the existing DbContext registration // VI: Xóa đăng ký DbContext hiện tại var descriptor = services.SingleOrDefault( - d => d.ServiceType == typeof(DbContextOptions)); + d => d.ServiceType == typeof(DbContextOptions)); if (descriptor != null) { @@ -31,7 +31,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory // EN: Remove DbContext service // VI: Xóa DbContext service var dbContextDescriptor = services.SingleOrDefault( - d => d.ServiceType == typeof(CatalogServiceContext)); + d => d.ServiceType == typeof(CatalogContext)); if (dbContextDescriptor != null) { @@ -40,7 +40,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory // EN: Add in-memory database for testing // VI: Thêm in-memory database để test - services.AddDbContext(options => + services.AddDbContext(options => { options.UseInMemoryDatabase("TestDatabase_" + Guid.NewGuid().ToString()); }); @@ -49,7 +49,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory // VI: Đảm bảo database được tạo với seed data var sp = services.BuildServiceProvider(); using var scope = sp.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); + var db = scope.ServiceProvider.GetRequiredService(); db.Database.EnsureCreated(); }); }