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 droit
surSnowfall.Data
->Add
->Directory
- Nommez le dossier
Context
Clic droit
surContext
->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
IConfiguration
contenant leConnectionString
est injecté dans le constructeur de la classe. - Lors de l'initialisation, on assigne à une variable privée
_connectionString
leConnectionString
AppDatabaseConnection
reç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 dureturn
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.
// 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.