9-6 DapperContext
L'architecture se définit de plus en plus, mais il existe toujours un aspect un peu agaçant dans EvenementRepository.
En effet, que ce soit dans GetAll() ou FindById(), on retrouve la ligne suivante:
using (IDbConnection connection = new NpgsqlConnection(
_configuration.GetConnectionString("AppDatabaseConnection")))
Imaginez que nous devions changer le nom de l'attribut AppDatabaseConnection du ConnectionString, il faudrait le changer dans toutes les fonctions de tous les repository. Ce serait fastidieux. Et au-delà de cet aspect, ce n'est pas très élégant non plus puisqu'on se répète.
Nous allons plutôt créer une classe DapperContext qu'on pourra utiliser pour obtenir une connexion. Il s'agira d'une classe avec des méthodes permettant de retourner des connexions à la base de données.
Le lien avec le ConnectionString sera géré dans cette classe.
Au fond, DapperContext est utilisé pour représenter une session avec la base de données et servir d'interface pour obtenir des connexions permettant de faire des requêtes à la BD.
Clic droitsurSnowfall.Data->Add->Directory- Nommez le dossier
Context Clic droitsurContext->Add->Class/Interface- Nommez la classe
DapperContext
Ensuite, voici le code pour la classe:
namespace Snowfall.Data.Context;
/// <summary>
/// Permets d'ouvrir et d'obtenir des connexions à la BD permettant de faire des requêtes.
/// </summary>
public class DapperContext
{
private readonly string _connectionString;
public DapperContext(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("AppDatabaseConnection")!;
}
/// <summary>
/// Crée une connexion à la BD
/// </summary>
/// <returns>Connexion IDbConnection</returns>
public IDbConnection CreateConnection()
{
var connection = new NpgsqlConnection(_connectionString);
connection.Open();
return connection;
}
}
- Dans un premier temps, l'objet de configuration
IConfigurationcontenant leConnectionStringest injecté dans le constructeur de la classe. - Lors de l'initialisation, on assigne à une variable privée
_connectionStringleConnectionStringAppDatabaseConnectionreçu via l'objetconfiguration. - Finalement, on crée une fonction qui retournent de nouvelles connexions à la BD.
- L'utilisation de fonction fléchée (
=>) est supportée depuis C# 6.0. Elle permet de créer des fonctions lambda, ainsi que d'éviter l'utilisation dureturnlorsqu'une fonction ne contient qu'une seule ligne et que cette ligne contient le retour de la fonction.
Ajout de DapperContext pour disponibilité à l'injection de dépendances
Comme nous avons fait pour EvenementRepository, ajoutons DapperContext au mécanisme d'injection de dépendances.
// Injection de dépendances
builder.Services.AddScoped<IEvenementRepository, EvenementRepository>();
builder.Services.AddSingleton<DapperContext>();
Comme DapperContext ne fait que créer des connexions via Npgsql, utiliser une seule instance pour toute l'application ne devrait pas poser problèmes. On utilise ainsi Singleton.
Utilisation de DapperContext dans EvenementRepository
On injecte DapperContext via le constructeur de EvenementRepository et on assigne la variable à une propriété privée _dbContext.
public class EvenementRepository : IEvenementRepository
{
private readonly DapperContext _dbContext;
public EvenementRepository(DapperContext dbContext)
{
_dbContext = dbContext;
}
//...
Ensuite, on peut remplacer les lignes de création de connexion (using (IDbConection...)) en appelant simplement _dbContext.CreateConnection().
GetAll()
public async Task<List<Evenement>> GetAll()
{
string sql = @"
SELECT * from evenements;
";
using (IDbConnection connection = _dbContext.CreateConnection())
{
IEnumerable<Evenement> evenements = await connection.QueryAsync<Evenement>(sql);
return evenements.ToList();
}
}
FindById()
public async Task<Evenement> FindById(int id)
{
string sql = @"
SELECT * from evenements
WHERE id = @Id;
";
using (IDbConnection connection = _dbContext.CreateConnection())
{
var param = new
{
Id = id
};
var evenement = await connection.QuerySingleOrDefaultAsync<Evenement>(sql, param);
return evenement;
}
}
Test
Une fois de plus, vous pouvez compiler et lancer le projet pour vous assurer que tout fonctionne correctement.