Ich habe mit Dapper gespielt, aber ich bin mir nicht sicher, wie ich am besten mit der Datenbankverbindung umgehen soll.
Die meisten Beispiele zeigen das Verbindungsobjekt, das in der Beispielklasse oder sogar in jeder Methode erstellt wird. Aber es fühlt sich für mich falsch an, in jedem clss eine Verbindungszeichenfolge zu referenzieren, auch wenn es aus der web.config zieht.
Meine Erfahrung ist mit der Verwendung eines DbDataContext
oder DbContext
mit Linq to SQL oder Entity Framework, also das ist neu für mich.
Wie strukturiere ich meine Web-Apps, wenn ich Dapper als meine Datenzugriffsstrategie verwende?
Microsoft.AspNetCore.All : v2.0.3 | Dapper : v1.50.2
Ich bin nicht sicher, ob ich die Best Practices richtig verwende oder nicht, aber ich mache es auf diese Weise, um mehrere Verbindungszeichenfolgen zu verarbeiten.
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);
}
// ......
}
}
Da Dapper
IDbConnection
, müssen Sie sich IDbConnection
, wie Sie verschiedene Datenbankverbindungen unterscheiden können.
Ich habe versucht , mehrere Schnittstellen zu schaffen, ‚geerbt‘ von IDbConnection
, um verschiedene Datenbankverbindungen entsprechen, und inject SqlConnection
mit verschiedenen Datenbank - Verbindungszeichenfolgen auf Startup
.
Das schlug fehl , weil SqlConnection
erbt von DbConnection
und DbConnection
inplements nicht nur IDbConnection
sondern auch Component
- Klasse. Daher können Ihre benutzerdefinierten Schnittstellen nicht nur die SqlConnection
Implementierung verwenden.
Ich habe auch versucht, eine eigene DbConnection
Klasse zu erstellen, die eine andere Verbindungszeichenfolge verwendet. Das ist zu kompliziert, da Sie alle Methoden der DbConnection
Klasse implementieren DbConnection
. Sie haben die Hilfe von SqlConnection
.
Startup
ich alle Verbindungszeichenfolgenwerte in ein Wörterbuch geladen. Ich habe auch eine enum
für alle Datenbankverbindungsnamen erstellt, um magische Zeichenfolgen zu vermeiden. IDbConnection
injizieren, habe ich IDbConnectionFactory
erstellt und diese als Transient für alle Repositorys injiziert. Jetzt verwenden alle Repositorys IDbConnectionFactory
anstelle von IDbConnection
. 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 - meine eigene Factory-Implementierung
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);
}
}
}
Für andere Repositorys, die mit den anderen Verbindungen kommunizieren müssen, können Sie dann eine andere Repository-Basisklasse für diese erstellen.
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);
}
// ......
}
}
Hoffe all diese Hilfe.