using System.Globalization; using System.Text; using AutoMapper; using CsvHelper; using MediatR; using ExpenseTracker.Application.Common.Exceptions; using ExpenseTracker.Application.Common.Interfaces.Repositories; using ExpenseTracker.Domain.Entities; namespace ExpenseTracker.Application.Accounts.Queries.Export.Csv.One; public class ExportCsvAccountQueryHandler : IRequestHandler { private readonly IMapper _mapper; private readonly IAccountRepository _accountRepository; private readonly ITransactionRepository _transactionRepository; public ExportCsvAccountQueryHandler( IMapper mapper, IAccountRepository repository, ITransactionRepository transactionRepository) { _mapper = mapper; _accountRepository = repository; _transactionRepository = transactionRepository; } public async Task Handle(ExportCsvAccountQuery request, CancellationToken cancellationToken) { var entity = _accountRepository.Queryable .GroupJoin( _transactionRepository.Queryable, b => b.Id, t => t.AccountId, (account, transactions) => new Account { Id = account.Id, Name = account.Name, Description = account.Description, UserId = account.UserId, Transactions = transactions } ) .FirstOrDefault(e => e.Id == request.Id); // TODO: Mapping to DTO creates new objects therefore using more resources // Create custom csv serializer to avoid mapping var entityDto = _mapper.Map(entity); using (var memoryStream = new MemoryStream()) { using (var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8)) { using (var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture)) { csvWriter.Context.RegisterClassMap(); await csvWriter.WriteRecordsAsync(entityDto.Transactions); await csvWriter.FlushAsync(); } } return memoryStream.ToArray(); } } }