= Напреден развој на апликација = == Pooling == Во backend слојот на !StockMaster апликацијата користиме ASP.NET Core со Entity Framework Core за комуникација со PostgreSQL базата на податоци. Поради оваа архитектура, конекциите со базата не се креираат рачно во кодот. Наместо тоа, тие автоматски се управуваат од Npgsql, кој е стандардниот .NET data provider за PostgreSQL. Connection pooling е вградена функционалност на Npgsql и е активирана по default. '''appsettings.json''' {{{ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "DefaultConnection": "Host=localhost;Database=StockDb;Username=YOUR_USERNAME;Password=YOUR_PASSWORD;Pooling=true;MinPoolSize=5;MaxPoolSize=100;Connection Idle Lifetime=300;" } } }}} '''Pooling=true''' Овозможува connection pooling, што значи дека базата ги реупотребува постоечките конекции наместо да креира нова конекција за секое барање. '''!MinPoolSize=5''' Го дефинира минималниот број на активни конекции што се одржуваат во connection pool при стартување на апликацијата. '''!MaxPoolSize=100''' Го ограничува максималниот број на истовремени конекции дозволени во connection pool при зголемен traffic. '''Connection Idle Lifetime=300''' Го одредува времето (во секунди) колку една неактивна конекција останува во pool пред автоматски да биде затворена и отстранета ако не се користи. == Трансакции == === 1. Креирање на продажба (!SaleService.cs) === Зошто Transaction? Кога се креира продажен запис, количината мора да се намали од залихата. Ако настане грешка при намалувањето на залихата, тогаш и продажниот запис не треба да се зачува, за да се обезбеди податоците да останат конзистентни. {{{ public async Task CreateSaleAsync(Sale sale) { using var transaction = await _context.Database.BeginTransactionAsync(); try { _context.Sales.Add(sale); await _context.SaveChangesAsync(); foreach (var item in sale.SaleItems) { var stock = await _context.WarehouseStocks .FirstOrDefaultAsync(ws => ws.WarehouseId == sale.WarehouseId && ws.ProductId == item.ProductId); if (stock == null || stock.QuantityOnHand < item.Quantity) { throw new Exception("Insufficient Stock"); } stock.QuantityOnHand -= item.Quantity; stock.LastUpdated = DateTime.Now; } await _context.SaveChangesAsync(); await transaction.CommitAsync(); return true; } catch { await transaction.RollbackAsync(); return false; } } }}}