Microsoft.AspNetCore.All : v2.0.3 | Dapper : v1.50.2
No estoy seguro de si estoy usando las mejores prácticas correctamente o no, pero lo estoy haciendo de esta manera, para manejar múltiples cadenas de conexión.
Es fácil si solo tiene 1 cadena de conexión
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)
{
string dbConnectionString = this.Configuration.GetConnectionString("dbConnection1");
services.AddTransient<IDbConnection>((sp) => new SqlConnection(dbConnectionString));
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";
return _dbConnection.Query<Diameter>(sql);
}
}
}
Problemas si tiene más de 1 cadena de conexión
Dado que se Dapper
utiliza IDbConnection
, debe pensar en una forma de diferenciar las diferentes conexiones de bases de datos.
Intenté crear múltiples interfaces, 'heredadas' de IDbConnection
, correspondientes a diferentes conexiones de base de datos, e inyectar SqlConnection
con diferentes cadenas de conexión de base de datos en Startup
.
Eso falló porque SqlConnection
hereda DbConnection
y DbConnection
complementa no solo IDbConnection
sino también la Component
clase. Por lo tanto, sus interfaces personalizadas no podrán usar solo la SqlConnection
implementación.
También intenté crear mi propia DbConnection
clase que toma una cadena de conexión diferente. Eso es demasiado complicado porque tienes que implementar todos los métodos de la DbConnection
clase. Perdiste la ayuda de SqlConnection
.
Lo que termino haciendo
- Durante
Startup
, cargué todos los valores de cadena de conexión en un diccionario. También creé un enum
para todos los nombres de conexión de la base de datos para evitar cadenas mágicas.
- Inyecté el diccionario como Singleton.
- En lugar de inyectar
IDbConnection
, lo creé IDbConnectionFactory
e inyecté como Transitorio para todos los repositorios. Ahora todos los repositorios toman en IDbConnectionFactory
lugar de IDbConnection
.
- ¿Cuándo elegir la conexión correcta? ¡En el constructor de todos los repositorios! Para hacer las cosas limpias, creé las clases base del repositorio y los repositorios heredaron de las clases base. La selección de la cadena de conexión correcta puede ocurrir en las clases 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 - mi propia implementación de fábrica
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") }
};
services.AddSingleton<IDictionary<DatabaseConnectionName, string>>(connectionDict);
services.AddTransient<IDbConnectionFactory, DapperDbConnectionFactory>();
services.AddScoped<IDiameterRepository, DiameterRepository>();
}
}
}
DiameterRepository.cs
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
public class DiameterRepository : DbConnection1RepositoryBase, IDiameterRepository
{
public DiameterRepository(IDbConnectionFactory dbConnectionFactory)
: base(dbConnectionFactory) { }
public IEnumerable<Diameter> GetAll()
{
const string sql = @"SELECT * FROM TABLE";
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)
{
this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection1);
}
}
}
Luego, para otros repositorios que necesitan comunicarse con las otras conexiones, puede crear una clase base de repositorio diferente para ellos.
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);
}
}
}
Espero que todos estos ayuden.