Aller au contenu principal

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.

  1. Clic droit sur Snowfall.Data -> Add -> Directory
  2. Nommez le dossier Context
  3. Clic droit sur Context -> Add -> Class/Interface
  4. Nommez la classe DapperContext

Ensuite, voici le code pour la classe:

Snowfall.Data/Context/DapperContext.cs
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;
}
}
info
  1. Dans un premier temps, l'objet de configuration IConfiguration contenant le ConnectionString est injecté dans le constructeur de la classe.
  2. Lors de l'initialisation, on assigne à une variable privée _connectionString le ConnectionString AppDatabaseConnection reçu via l'objet configuration.
  3. Finalement, on crée une fonction qui retournent de nouvelles connexions à la BD.
  4. 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 du return lorsqu'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.

Snowfall.Web.Mvc/Program.cs
// Injection de dépendances
builder.Services.AddScoped<IEvenementRepository, EvenementRepository>();
builder.Services.AddSingleton<DapperContext>();
info

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.

Snowfall.Data/Repositories/EvenementRepository.cs
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()

Snowfall.Data/Repositories/EvenementRepository.cs
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()

Snowfall.Data/Repositories/EvenementRepository.cs
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.