Mise à jour : clarification à partir du commentaire de MarredCheese :
"Il n'est pas nécessaire d'utiliser une déclaration d'utilisation. Dapper ouvrira, fermera et éliminera automatiquement la connexion pour vous, fermera et éliminera la connexion pour vous". Ce n'est pas correct. Dapper ouvrira automatiquement les connexions fermées, et il fermera automatiquement les connexions fermées. automatiquement les connexions fermées qu'il s'est ouvert automatiquement mais il ne le fera pas automatiquement les connexions. Marc Gravell et Eric Lippert préconisent tous deux l'utilisation de Dapper aquí .
Microsoft.AspNetCore.All : v2.0.3 | Dapper : v1.50.2
Je ne sais pas si j'utilise les meilleures pratiques correctement ou non, mais je procède de cette manière, afin de gérer multiples chaînes de connexion.
C'est facile si vous n'avez qu'une seule chaîne de connexion
Startup.cs
using System.Data;
using System.Data.SqlClient;
namespace DL.SO.Project.Web.UI
{
public class Startup
{
public IConfiguration Configuration { get; private set; }
// ......
public void ConfigureServices(IServiceCollection services)
{
// Read the connection string from appsettings.
string dbConnectionString = this.Configuration.GetConnectionString("dbConnection1");
// Inject IDbConnection, with implementation from SqlConnection class.
services.AddTransient<IDbConnection>((sp) => new SqlConnection(dbConnectionString));
// Register your regular repositories
services.AddScoped<IDiameterRepository, DiameterRepository>();
// ......
}
}
}
DiameterRepository.cs
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
public class DiameterRepository : IDiameterRepository
{
private readonly IDbConnection _dbConnection;
public DiameterRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public IEnumerable<Diameter> GetAll()
{
const string sql = @"SELECT * FROM TABLE";
// No need to use using statement. Dapper will automatically
// open, close and dispose the connection for you.
return _dbConnection.Query<Diameter>(sql);
}
// ......
}
}
Problèmes si vous avez plus d'une chaîne de connexion
Depuis Dapper
utilise IDbConnection
il faut trouver un moyen de différencier les différentes connexions à la base de données.
J'ai essayé de créer plusieurs interfaces, "héritées" de IDbConnection
correspondant à différentes connexions à la base de données, et injecter SqlConnection
avec des chaînes de connexion à la base de données différentes sur Startup
.
Cet échec s'explique par le fait que SqlConnection
hérite de DbConnection
y DbConnection
Les compléments ne se limitent pas seulement à l'aide à la recherche et au développement. IDbConnection
mais aussi Component
classe. Vos interfaces personnalisées ne pourront donc pas utiliser uniquement la classe SqlConnection
l'implémentation.
J'ai également essayé de créer ma propre DbConnection
qui prend une chaîne de connexion différente. C'est trop compliqué car il faut implémenter toutes les méthodes de DbConnection
classe. Vous avez perdu l'aide de SqlConnection
.
Ce que je fais en fin de compte
- Pendant
Startup
J'ai chargé toutes les valeurs des chaînes de connexion dans un dictionnaire. J'ai également créé un fichier enum
pour tous les noms de connexion à la base de données afin d'éviter les chaînes magiques.
- J'ai injecté le dictionnaire en tant que Singleton.
- Au lieu d'injecter
IDbConnection
J'ai créé IDbConnectionFactory
et l'injecter en tant que transitoire pour tous les dépôts. Maintenant, tous les dépôts prennent IDbConnectionFactory
au lieu de IDbConnection
.
- Quand choisir la bonne connexion ? Dans le constructeur de tous les référentiels ! Pour faire les choses proprement, j'ai créé des classes de base pour les référentiels et j'ai fait en sorte que les référentiels héritent des classes de base. La sélection de la bonne chaîne de connexion peut se faire dans les classes de base.
DatabaseConnectionName.cs
namespace DL.SO.Project.Domain.Repositories
{
public enum DatabaseConnectionName
{
Connection1,
Connection2
}
}
IDbConnectionFactory.cs
using System.Data;
namespace DL.SO.Project.Domain.Repositories
{
public interface IDbConnectionFactory
{
IDbConnection CreateDbConnection(DatabaseConnectionName connectionName);
}
}
DapperDbConenctionFactory - ma propre implémentation de la fabrique
namespace DL.SO.Project.Persistence.Dapper
{
public class DapperDbConnectionFactory : IDbConnectionFactory
{
private readonly IDictionary<DatabaseConnectionName, string> _connectionDict;
public DapperDbConnectionFactory(IDictionary<DatabaseConnectionName, string> connectionDict)
{
_connectionDict = connectionDict;
}
public IDbConnection CreateDbConnection(DatabaseConnectionName connectionName)
{
string connectionString = null;
if (_connectDict.TryGetValue(connectionName, out connectionString))
{
return new SqlConnection(connectionString);
}
throw new ArgumentNullException();
}
}
}
Startup.cs
namespace DL.SO.Project.Web.UI
{
public class Startup
{
// ......
public void ConfigureServices(IServiceCollection services)
{
var connectionDict = new Dictionary<DatabaseConnectionName, string>
{
{ DatabaseConnectionName.Connection1, this.Configuration.GetConnectionString("dbConnection1") },
{ DatabaseConnectionName.Connection2, this.Configuration.GetConnectionString("dbConnection2") }
};
// Inject this dict
services.AddSingleton<IDictionary<DatabaseConnectionName, string>>(connectionDict);
// Inject the factory
services.AddTransient<IDbConnectionFactory, DapperDbConnectionFactory>();
// Register your regular repositories
services.AddScoped<IDiameterRepository, DiameterRepository>();
// ......
}
}
}
DiameterRepository.cs
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
// Move the responsibility of picking the right connection string
// into an abstract base class so that I don't have to duplicate
// the right connection selection code in each repository.
public class DiameterRepository : DbConnection1RepositoryBase, IDiameterRepository
{
public DiameterRepository(IDbConnectionFactory dbConnectionFactory)
: base(dbConnectionFactory) { }
public IEnumerable<Diameter> GetAll()
{
const string sql = @"SELECT * FROM TABLE";
// No need to use using statement. Dapper will automatically
// open, close and dispose the connection for you.
return base.DbConnection.Query<Diameter>(sql);
}
// ......
}
}
DbConnection1RepositoryBase.cs
using System.Data;
using DL.SO.Project.Domain.Repositories;
namespace DL.SO.Project.Persistence.Dapper
{
public abstract class DbConnection1RepositoryBase
{
public IDbConnection DbConnection { get; private set; }
public DbConnection1RepositoryBase(IDbConnectionFactory dbConnectionFactory)
{
// Now it's the time to pick the right connection string!
// Enum is used. No magic string!
this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection1);
}
}
}
Ensuite, pour les autres référentiels qui ont besoin de communiquer avec les autres connexions, vous pouvez créer une classe de base de référentiel différente pour eux.
using System.Data;
using DL.SO.Project.Domain.Repositories;
namespace DL.SO.Project.Persistence.Dapper
{
public abstract class DbConnection2RepositoryBase
{
public IDbConnection DbConnection { get; private set; }
public DbConnection2RepositoryBase(IDbConnectionFactory dbConnectionFactory)
{
this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection2);
}
}
}
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
public class ParameterRepository : DbConnection2RepositoryBase, IParameterRepository
{
public ParameterRepository (IDbConnectionFactory dbConnectionFactory)
: base(dbConnectionFactory) { }
public IEnumerable<Parameter> GetAll()
{
const string sql = @"SELECT * FROM TABLE";
return base.DbConnection.Query<Parameter>(sql);
}
// ......
}
}
J'espère que tout cela vous aidera.