wiki:AdvancedApplicationDevelopment

Version 3 (modified by 221181, 4 hours ago) ( diff )

--

Напреден развој на апликација

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<bool> 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;
    }
}

2. Примање на нарачка (PurchaseOrderService.cs)

Зошто Transaction?

Кога статусот на нарачката се менува во „Received“, залихите мора да се зголемат. Ако едната операција се изврши, а другата не, ќе настане неконзистентност во податоците.

public async Task<bool> ReceivePurchaseOrderAsync(int poId)
{
    using var transaction = await _context.Database.BeginTransactionAsync();
    try
    {
        var po = await GetPurchaseOrderByIdAsync(poId);
        if (po == null || po.Status == "Received")
            return false;

        
        foreach (var item in po.PurchaseOrderItems)
        {
            var stock = await _context.WarehouseStocks
                .FirstOrDefaultAsync(ws => ws.WarehouseId == po.WarehouseId && ws.ProductId == item.ProductId);

            if (stock == null)
            {
                stock = new WarehouseStock
                {
                    WarehouseId = po.WarehouseId,
                    ProductId = item.ProductId,
                    QuantityOnHand = item.Quantity
                };
                _context.WarehouseStocks.Add(stock);
            }
            else
            {
                stock.QuantityOnHand += item.Quantity;
            }

            stock.LastUpdated = DateTime.Now;
            item.ReceivedQuantity = item.Quantity;
        }

        po.Status = "Received";
        po.ActualDeliveryDate = DateTime.Now.Date;

        await _context.SaveChangesAsync();
        await transaction.CommitAsync();
        return true;
    }
    catch
    {
        await transaction.RollbackAsync();
        return false;
    }
}
Note: See TracWiki for help on using the wiki.