Pattern Repository et Unit of Work - Exemple concret : Plateforme e-commerce

Étude de cas : découvrez l’utilisation conjointe des deux patterns pour gérer commandes, stocks, et paiements dans une plateforme e-commerce.

Sommaire

Cet article fait partie d'une série de plusieurs articles sur les patterns Repository et Unit of Work :

Prenons l’exemple d’une application de gestion de commandes dans une plateforme e-commerce. Voici comment les patterns Repository et Unit of Work peuvent être utilisés ensemble :

Scénario : Création d’une commande

  1. Une commande contient des informations sur le client, les articles commandés, et le montant total.
  2. L’opération doit :
    • Créer une nouvelle commande.
    • Mettre à jour l’inventaire pour les articles concernés.
    • Enregistrer la transaction de paiement.

Code d’implémentation

public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;

    public OrderService(IUnitOfWork unitOfWork)
    {
        // Injection de l'UnitOfWork pour coordonner les transactions
        _unitOfWork = unitOfWork;
    }

    public async Task<bool> CreateOrderAsync(Order order, IEnumerable<OrderItem> orderItems)
    {
        try
        {
            // Étape 1 : Ajouter la commande
            await _unitOfWork.Repository<Order>().AddAsync(order);

            // Étape 2 : Mettre à jour l'inventaire pour chaque article commandé
            foreach (var item in orderItems)
            {
                var product = await _unitOfWork.Repository<Product>().GetByIdAsync(item.ProductId);
                if (product == null || product.Stock < item.Quantity)
                {
                    throw new InvalidOperationException("Stock insuffisant.");
                }

                product.Stock -= item.Quantity; // Réduction du stock
                _unitOfWork.Repository<Product>().Update(product);
            }

            // Étape 3 : Enregistrer la transaction de paiement
            var payment = new Payment
            {
                OrderId = order.Id,
                Amount = orderItems.Sum(i => i.Price * i.Quantity),
                PaymentDate = DateTime.UtcNow
            };
            await _unitOfWork.Repository<Payment>().AddAsync(payment);

            // Étape 4 : Sauvegarder toutes les modifications dans une transaction unique
            await _unitOfWork.SaveChangesAsync();

            return true; // Retourne vrai si tout s'est bien passé
        }
        catch (Exception)
        {
            // Gestion des erreurs : la transaction sera annulée en cas d'exception
            throw;
        }
    }
}

Explications

  • Isolation de la logique : Chaque repository gère une entité spécifique (Order, Product, Payment).
  • Transaction unique : Toutes les opérations sont regroupées via l’Unit of Work, garantissant la cohérence des données.
  • Facilité de maintenance : La logique d’application reste claire et bien structurée.

A suivre : Conclusion et retour d'expérience