使用.NET Core的Dapper - 注入SqlConnection生命周期/范围

Phi*_* P. 11 c# dependency-injection dapper asp.net-core

我正在使用.NET Core Dependency Injection SqlConnection在应用程序启动期间实例化一个对象,然后我计划将其注入我的存储库.这SqlConnection将由Dapper用于在我的存储库实现中读取/写入数据库中的数据.我将使用asyncDapper调用.

问题是:我应该注入SqlConnection瞬态还是单身?考虑到我想使用async我的想法的事实将是使用瞬态,除非Dapper在内部实现一些隔离容器,并且我的单例的范围仍将被包装在Dapper内部使用的范围内.

在使用Dapper时,是否有关于SqlConnection对象生命周期的建议/最佳实践?有什么警告我可能会丢失吗?

提前致谢.

And*_*nov 6

如果您以单例方式提供SQL连接,则除非启用MARS,否则将无法同时处理多个请求,这也有其局限性。最佳实践是使用临时SQL连接并确保正确处理它。

在我的应用程序中,我将自定义传递IDbConnectionFactory给用于创建using语句内部连接的存储库。在这种情况下,存储库本身可以是单例的,以减少堆上的分配。

  • 我想同一个存储库将使用与单个数据源的连接。在这种情况下,我将采用数据源特定连接工厂的方法。工厂的接口可以相同,只是特定于 DB 的实现。 (2认同)
  • @EmranHussain,是的,注入单例的瞬态服务的逻辑是正确的。在我的回答中,我并不是指将 SQL 连接注入到工厂中,而是指要注入的连接字符串以及工厂从连接字符串创建的 SQL 连接。 (2认同)

rob*_*pim 5

很好的问题,已经有两个很好的答案了。起初我对此感到困惑,并提出了以下解决方案来解决该问题,它将存储库封装在管理器中。管理器本身负责提取连接字符串并将其注入存储库。

我发现这种方法可以使单独测试存储库(例如在模拟控制台应用程序中)变得更加简单,而且我在几个大型项目中遵循这种模式非常幸运。尽管我承认我不是测试、依赖注入或任何其他方面的专家!

我问自己的主要问题是 DbService 是否应该是单例。我的理由是,不断创建和销毁封装的各种存储库没有多大意义DbService,因为它们都是无状态的,所以我认为允许它们“生存”没有太大问题。尽管这可能是完全无效的逻辑。

编辑:如果您想要一个现成的解决方案,请查看我在GitHub上的 Dapper 存储库实现

存储库管理器的结构如下:

/*
 * Db Service
 */
public interface IDbService
{
    ISomeRepo SomeRepo { get; }
}

public class DbService : IDbService
{
    readonly string connStr;
    ISomeRepo someRepo;

    public DbService(string connStr)
    {
        this.connStr = connStr;
    }

    public ISomeRepo SomeRepo
    {
        get
        {
            if (someRepo == null)
            {
                someRepo = new SomeRepo(this.connStr);
            }

            return someRepo;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

示例存储库的结构如下:

/*
 * Mock Repo
 */
public interface ISomeRepo
{
    IEnumerable<SomeModel> List();
}

public class SomeRepo : ISomeRepo
{
    readonly string connStr;

    public SomeRepo(string connStr)
    {
        this.connStr = connStr;
    }

    public IEnumerable<SomeModel> List()
    {
        //work to return list of SomeModel 
    }
}
Run Code Online (Sandbox Code Playgroud)

将其全部连接起来:

/*
 * Startup.cs
 */
public IConfigurationRoot Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    //...rest of services

    services.AddSingleton<IDbService, DbService>();

    //...rest of services
}
Run Code Online (Sandbox Code Playgroud)

最后,使用它:

public SomeController : Controller 
{
    IDbService dbService;

    public SomeController(IDbService dbService)
    {
        this.dbService = dbService;
    }

    public IActionResult Index()
    {
        return View(dbService.SomeRepo.List());
    }
}
Run Code Online (Sandbox Code Playgroud)