简单但很好的例子,如何使用Dapper与Structuremap和依赖注入
本文关键字:Dapper Structuremap 注入 依赖 何使用 很好 简单 | 更新日期: 2023-09-27 18:15:14
我试图了解如何使用依赖注入与Dapper (IDbConnection),仍然能够使用内置处置。
我在网上找到了几篇文章,但没有一篇我认为是容易理解的。
我想弄清楚的是如何使这个简单的类是可测试的:
public class UserProfileRepository : IUserProfileRepository
{
private readonly IConfigRepository _configRepository;
public UserProfileRepository(IConfigRepository configRepository)
{
_configRepository = configRepository;
}
public UserProfile GetUserProfile(string userId)
{
const string query = @"Select UserId, UserName
From Users
Where UserId = @UserId";
using (var conn = new SqlConnection(_configRepository.GetConnectionString("MyConnectionString")))
{
conn.Open();
return conn.Query<UserProfile>(query, new { UserId = userId }).SingleOrDefault();
}
}
}
我有一个配置存储库,看起来像这样,所以我可以模拟web请求。配置:
public class ConfigRepository : IConfigRepository
{
public string GetConnectionString(string key)
{
var conString = ConfigurationManager.ConnectionStrings[key];
if (conString != null)
{
return conString.ConnectionString;
}
return string.Empty;
}
}
我已经读到,你可以使用ConnectionFactory,但还没有弄清楚如何实现它,仍然知道我处置它正确。
谁能给我指个正确的方向?根据我的经验,最好的连接创建机制是DependencyInjection
和ConnectionFactory
的组合。我正在摆脱IConfigRepository
,因为这里所有的工作都是使用工厂完成的
优势多褶皱:
- 在运行时在事务或线程范围内创建连接对象
- 在运行时更改系统的数据提供者和数据库(使用连接工厂)
你应当做什么(在代码中):
在数据访问层声明IDBConnection
对象:
[Inject] // Property Injection
public IDBConnection Connection {get; set;}
使用像Ninject这样的DI框架声明绑定:
Bind<IDBConnection>().ToMethod(ctx =>
ConnectionFactory.CreateDbConnection("DefaultConnection"));
按如下方式创建DBConnection工厂:
连接工厂从配置文件中获取连接提供者和连接字符串,如下所示:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=<Value>;Initial Catalog=<Value>;User Id=<Value>;Password=<Value>" providerName="System.Data.SqlClient" />
</connectionStrings>
标识符是DefaultConnection
,它使用SqlClient提供程序,但在运行时可以更改为不同的客户端,如Oracle, MySql
using System;
using System.Data.Common;
public static class ConnectionFactory
{
/// <summary>
/// Create DBConnection type based on provider name and connection string
/// </summary>
/// <param name="connectionIdentifier"></param>
/// <returns></returns>
public static DbConnection CreateDbConnection(string connectionIdentifier)
{
// Provider name setting
var providerNameValue = ConfigurationManager.ConnectionStrings[connectionIdentifier].ProviderName;
// Connection string setting
var connectionStringValue = ConfigurationManager.ConnectionStrings[connectionIdentifier].ConnectionString;
// Assume failure.
DbConnection connection;
// Null connection string cannot be accepted
if (connectionStringValue == null) return null;
// Create the DbProviderFactory and DbConnection.
try
{
// Fetch provider factory
var factory = DbProviderFactories.GetFactory(providerNameValue);
// Create Connection
connection = factory.CreateConnection();
// Assign connection string
if (connection != null)
connection.ConnectionString = connectionStringValue;
}
catch (Exception ex)
{
connection = null;
}
// Return the connection.
return connection;
}
}
如何使用:
对于单个调用和处置
using(Connection)
{
...
}
对于Transaction上下文,按原样使用,不需要using
关于嘲笑:
无论您使用哪个Mock框架进行单元测试,您都必须模拟UserProfileRepository :: GetUserProfile(string userId)
的结果,这将比使用依赖注入填充MockConnection
更容易,这将使其变得复杂。DI适用于实际用例,用于在运行时填充连接对象