Nous passerons en revue le modèle de conception d’unité de travail à l’aide d’un référentiel générique et une implémentation étape par étape à l’aide de l’API Web .NET Core 6.
Conditions préalables
- Visual Studio 2022
- serveur SQL
- SDK .NET Core 6
Modèle de référentiel
- Le modèle de référentiel est utilisé pour créer une couche d’abstraction entre la couche d’accès aux données et la couche métier d’une application.
- Ce modèle aide à réduire la duplication de code et suit le principe DRY.
- Cela aide également à créer un couplage lâche entre plusieurs composants; lorsque nous voulons changer quelque chose à l’intérieur de la couche d’accès aux données, ce temps n’a pas besoin de changer une autre couche où nous consommons cette fonctionnalité.
- La séparation des préoccupations facilite la maintenance du code.
- La mise en œuvre de modèles de référentiel nous aide à écrire des cas de test unitaires de manière efficace et simple.
Unité de travail
- Le modèle de référentiel nous aide à créer une abstraction, à découpler le code et à éviter le code redondant.
Figure : Le schéma provient de la documentation technique de Microsoft.
- Mais parfois, cela peut partiellement mettre à jour les données car lorsque l’application est énorme, les référentiels partagent le même contexte de base de données dans toute l’application et effectuent des opérations telles que l’insertion, la mise à jour et la lecture. Ainsi, dans ce cas, il pourrait y avoir une chance d’échouer certaines transactions, et peu sont exécutées avec succès en raison de problèmes de concurrence. Donc, pour cette raison, nous utilisons une unité de travail pour maintenir l’intégrité des données à l’intérieur de l’application.
- De plus, l’unité de travail gère une base de données en mémoire lorsque nous effectuons des opérations CRUD sur certaines classes d’entités en une seule transaction. Si certaines opérations de base de données échouent, toutes les opérations seront annulées.
- Cela permet également de créer des couches faiblement couplées à l’aide de l’injection de dépendances et de suivre les principes de développement piloté par les tests (TDD).
Mise en œuvre étape par étape
Étape 1
Créez une nouvelle API Web .NET Core.
Étape 2
Configurez votre application.
Étape 3
Fournissez quelques détails supplémentaires.
Structure du projet.
Étape 4
Créez trois projets de bibliothèque de classes dans la solution principale.

Étape 5
Ensuite, ajoutez une classe de modèle dans le projet UnitOfWorkDemo.Core et ajoutez également quelques interfaces.

ProductDetails.cs
namespace UnitOfWorkDemo.Core.Models
{
public class ProductDetails
{
public int Id { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public int ProductPrice { get; set; }
public int ProductStock { get; set; }
}
}
IGenericRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnitOfWorkDemo.Core.Interfaces
{
public interface IGenericRepository<T> where T : class
{
Task<T> GetById(int id);
Task<IEnumerable<T>> GetAll();
Task Add(T entity);
void Delete(T entity);
void Update(T entity);
}
}
IProductRepository.cs
using UnitOfWorkDemo.Core.Models;
namespace UnitOfWorkDemo.Core.Interfaces
{
public interface IProductRepository : IGenericRepository<ProductDetails>
{
}
}
IUnitOfWork.cs
namespace UnitOfWorkDemo.Core.Interfaces
{
public interface IUnitOfWork : IDisposable
{
IProductRepository Products { get; }
int Save();
}
}
Étape 6
Maintenant, nous allons ajouter une implémentation de tous les référentiels que nous avons créés précédemment et également créer une DbContextClass à l’intérieur.

Fichier de projet
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\UnitOfWorkDemo.Core\UnitOfWorkDemo.Core.csproj" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8" />
</ItemGroup>
</Project>
GenericRepository.cs
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkDemo.Core.Interfaces;
namespace UnitOfWorkDemo.Infrastructure.Repositories
{
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected readonly DbContextClass _dbContext;
protected GenericRepository(DbContextClass context)
{
_dbContext = context;
}
public async Task<T> GetById(int id)
{
return await _dbContext.Set<T>().FindAsync(id);
}
public async Task<IEnumerable<T>> GetAll()
{
return await _dbContext.Set<T>().ToListAsync();
}
public async Task Add(T entity)
{
await _dbContext.Set<T>().AddAsync(entity);
}
public void Delete(T entity)
{
_dbContext.Set<T>().Remove(entity);
}
public void Update(T entity)
{
_dbContext.Set<T>().Update(entity);
}
}
}
ProductRepository.cs
using UnitOfWorkDemo.Core.Interfaces;
using UnitOfWorkDemo.Core.Models;
namespace UnitOfWorkDemo.Infrastructure.Repositories
{
public class ProductRepository : GenericRepository<ProductDetails>, IProductRepository
{
public ProductRepository(DbContextClass dbContext) : base(dbContext)
{
}
}
}
UnitOfWork.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkDemo.Core.Interfaces;
namespace UnitOfWorkDemo.Infrastructure.Repositories
{
public class UnitOfWork : IUnitOfWork
{
private readonly DbContextClass _dbContext;
public IProductRepository Products { get; }
public UnitOfWork(DbContextClass dbContext,
IProductRepository productRepository)
{
_dbContext = dbContext;
Products = productRepository;
}
public int Save()
{
return _dbContext.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_dbContext.Dispose();
}
}
}
}
DbContextClass.csDbContextClass.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkDemo.Core.Models;
namespace UnitOfWorkDemo.Infrastructure
{
public class DbContextClass : DbContext
{
public DbContextClass(DbContextOptions<DbContextClass> contextOptions) : base(contextOptions)
{
}
public DbSet<ProductDetails> Products { get; set; }
}
}
Après cela, créez une classe d’extension pour laquelle nous avons l’habitude d’enregistrer les services DI et configurez-la dans le fichier Program.cs du projet racine.
ServiceExtension.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkDemo.Core.Interfaces;
using UnitOfWorkDemo.Infrastructure.Repositories;
namespace UnitOfWorkDemo.Infrastructure.ServiceExtension
{
public static class ServiceExtension
{
public static IServiceCollection AddDIServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<DbContextClass>(options =>
{
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
});
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<IProductRepository, ProductRepository>();
return services;
}
}
}
Ensuite, ajoutez la migration et mettez à jour la base de données dans le projet d’infrastructure à l’aide de la commande suivante.
add-migration “v1”
update-database
Étape 5
Ensuite, créez un service de produit dans le projet Services, que nous injectons et consommons dans le contrôleur principal.

IProductService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkDemo.Core.Models;
namespace UnitOfWorkDemo.Services.Interfaces
{
public interface IProductService
{
Task<bool> CreateProduct(ProductDetails productDetails);
Task<IEnumerable<ProductDetails>> GetAllProducts();
Task<ProductDetails> GetProductById(int productId);
Task<bool> UpdateProduct(ProductDetails productDetails);
Task<bool> DeleteProduct(int productId);
}
}
ProductService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitOfWorkDemo.Core.Interfaces;
using UnitOfWorkDemo.Core.Models;
using UnitOfWorkDemo.Services.Interfaces;
namespace UnitOfWorkDemo.Services
{
public class ProductService : IProductService
{
public IUnitOfWork _unitOfWork;
public ProductService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<bool> CreateProduct(ProductDetails productDetails)
{
if...