168 lines
5.3 KiB
C#
168 lines
5.3 KiB
C#
using MediatR;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|
using AdsAnalyticsService.Domain.AggregatesModel.MetricsAggregate;
|
|
using AdsAnalyticsService.Domain.AggregatesModel.ReportAggregate;
|
|
using AdsAnalyticsService.Domain.SeedWork;
|
|
using AdsAnalyticsService.Infrastructure.EntityConfigurations;
|
|
|
|
namespace AdsAnalyticsService.Infrastructure;
|
|
|
|
/// <summary>
|
|
/// EN: EF Core DbContext for AdsAnalyticsService.
|
|
/// VI: EF Core DbContext cho AdsAnalyticsService.
|
|
/// </summary>
|
|
public class AdsAnalyticsServiceContext : DbContext, IUnitOfWork
|
|
{
|
|
private readonly IMediator _mediator;
|
|
private IDbContextTransaction? _currentTransaction;
|
|
|
|
/// <summary>
|
|
/// EN: Campaign metrics table.
|
|
/// VI: Bảng metrics chiến dịch.
|
|
/// </summary>
|
|
public DbSet<CampaignMetrics> CampaignMetrics => Set<CampaignMetrics>();
|
|
|
|
/// <summary>
|
|
/// EN: Reports table.
|
|
/// VI: Bảng báo cáo.
|
|
/// </summary>
|
|
public DbSet<Report> Reports => Set<Report>();
|
|
|
|
/// <summary>
|
|
/// EN: Read-only access to current transaction.
|
|
/// VI: Truy cập chỉ đọc đến transaction hiện tại.
|
|
/// </summary>
|
|
public IDbContextTransaction? CurrentTransaction => _currentTransaction;
|
|
|
|
/// <summary>
|
|
/// EN: Check if there is an active transaction.
|
|
/// VI: Kiểm tra xem có transaction đang hoạt động không.
|
|
/// </summary>
|
|
public bool HasActiveTransaction => _currentTransaction != null;
|
|
|
|
public AdsAnalyticsServiceContext(DbContextOptions<AdsAnalyticsServiceContext> options) : base(options)
|
|
{
|
|
_mediator = null!;
|
|
}
|
|
|
|
public AdsAnalyticsServiceContext(DbContextOptions<AdsAnalyticsServiceContext> options, IMediator mediator) : base(options)
|
|
{
|
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
|
|
|
System.Diagnostics.Debug.WriteLine("AdsAnalyticsServiceContext::ctor - " + GetHashCode());
|
|
}
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
// EN: Apply entity configurations
|
|
// VI: Áp dụng các cấu hình entity
|
|
modelBuilder.ApplyConfiguration(new CampaignMetricsEntityTypeConfiguration());
|
|
modelBuilder.ApplyConfiguration(new ReportEntityTypeConfiguration());
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Save entities and dispatch domain events.
|
|
/// VI: Lưu entities và dispatch domain events.
|
|
/// </summary>
|
|
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
// EN: Dispatch domain events before saving (side effects)
|
|
// VI: Dispatch domain events trước khi lưu (side effects)
|
|
await DispatchDomainEventsAsync();
|
|
|
|
// EN: Save changes to database
|
|
// VI: Lưu thay đổi vào database
|
|
await base.SaveChangesAsync(cancellationToken);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Begin a new transaction if none is active.
|
|
/// VI: Bắt đầu một transaction mới nếu không có transaction nào đang hoạt động.
|
|
/// </summary>
|
|
public async Task<IDbContextTransaction?> BeginTransactionAsync()
|
|
{
|
|
if (_currentTransaction != null) return null;
|
|
|
|
_currentTransaction = await Database.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);
|
|
|
|
return _currentTransaction;
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Commit the current transaction.
|
|
/// VI: Commit transaction hiện tại.
|
|
/// </summary>
|
|
public async Task CommitTransactionAsync(IDbContextTransaction transaction)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(transaction);
|
|
|
|
if (transaction != _currentTransaction)
|
|
throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
|
|
|
|
try
|
|
{
|
|
await SaveChangesAsync();
|
|
await transaction.CommitAsync();
|
|
}
|
|
catch
|
|
{
|
|
RollbackTransaction();
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
if (_currentTransaction != null)
|
|
{
|
|
_currentTransaction.Dispose();
|
|
_currentTransaction = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Rollback the current transaction.
|
|
/// VI: Rollback transaction hiện tại.
|
|
/// </summary>
|
|
public void RollbackTransaction()
|
|
{
|
|
try
|
|
{
|
|
_currentTransaction?.Rollback();
|
|
}
|
|
finally
|
|
{
|
|
if (_currentTransaction != null)
|
|
{
|
|
_currentTransaction.Dispose();
|
|
_currentTransaction = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Dispatch all domain events from tracked entities.
|
|
/// VI: Dispatch tất cả domain events từ các entities đang được track.
|
|
/// </summary>
|
|
private async Task DispatchDomainEventsAsync()
|
|
{
|
|
var domainEntities = ChangeTracker
|
|
.Entries<Entity>()
|
|
.Where(x => x.Entity.DomainEvents.Any())
|
|
.ToList();
|
|
|
|
var domainEvents = domainEntities
|
|
.SelectMany(x => x.Entity.DomainEvents)
|
|
.ToList();
|
|
|
|
domainEntities.ForEach(entity => entity.Entity.ClearDomainEvents());
|
|
|
|
foreach (var domainEvent in domainEvents)
|
|
{
|
|
await _mediator.Publish(domainEvent);
|
|
}
|
|
}
|
|
}
|