TLDR:为什么要注入连接工厂而不是IDbConnection本身。
我目前正在使用.net MVC中的Autofac将IDbConnection实例注入到存储库类中,以便与Dapper一起使用,如下所示:
Autofac设置:
builder.Register<IDbConnection>(ctx => new
SqlConnection(conSettings.ConnectionString)).InstancePerRequest();回购:
public ClientRepository(IDbConnection connection)
{
_connection = connection;
}
public async Task<IEnumerable<Client>> GetAsync()
{
string query = "SELECT * FROM Clients";
return (await _connection.QueryAsync<Client>(query)).ToList();
}到目前为止,这对我来说一直都很好,但我有点担心连接会一直保持开放,不会被处理掉。
我在这个主题上找到的每一篇文章都以建议传递连接工厂并在using语句中调用它而告终,而没有真正提到为什么我当前的设置是“糟糕的”。
据我所知,每个请求都应该得到自己的IDbConnection,其中Dapper负责打开和关闭连接,Autofac负责处理。
不是这样的吗?我是不是遗漏了什么?
发布于 2019-05-09 12:59:30
如果您只注入IDbConnection,这意味着您的存储库只能使用这一连接,并且您依赖于IoC来关闭/处理该连接。另外,如果您需要连接到两个不同的数据库,则不能这样做,因为您只允许在这里创建一个连接。如果希望并行运行查询,则不能这样做,因为每次只能对单个数据库进行一个打开的调用。最后,如果获得连接字符串有点困难,并且不是直接从配置文件(如KeyVault)获得,那么您需要调用外部异步方法,或者IoC可能不允许您做的事情。
对我来说,我总是使用工厂,因为我想在完成连接后立即关闭连接,而不是等待IoC处理掉它。(允许存储库之外的东西管理数据库连接是很脏的。)我想要控制连接到哪个数据库(我经常有超过1DB的数据库需要处理)。为了返回所需的所有数据,我偶尔需要并行运行一系列不同的查询,因此我需要在一个方法中进行多个连接。我还必须做一些逻辑,因为我们将连接字符串存储在Azure Key Vault中,所以我必须执行异步调用才能得到带有秘密信息的异步调用,这有点复杂,所以工厂上的Create方法最终做了很多工作。
发布于 2022-10-27 22:20:10
我完全同意,这里的建议似乎一贯倾向于向工厂注入而不是注入连接,而且很难找到很多关于原因的讨论。
我认为,在简单的情况下,容器插入连接本身是很好的,这很简单,并且可以立即减轻100%重复的样板:using var conn = _connFactory.Make()。
但是,让容器注入一个工厂的好处是,它使您能够更好地控制连接创建/生存期。此控件真正重要的一个常见情况是何时要使用TransactionScope。由于必须在要参与事务的任何连接之前实例化它,所以使用DI容器提前创建连接是没有意义的。Daniel提出了其他几种情况,您可能需要对his answer中的连接创建进行精细控制。
如果您决定使用DbConnection.BeginTransaction而不是TransactionScope来管理事务(通常不推荐),那么您需要在事务中涉及的所有查询/方法/类之间共享DbConnection/DbTransaction实例。在这种情况下,到处注入连接工厂并让类做自己的事情将不再起作用。一个合理的解决方案是将连接或连接工厂(哪一种并不重要)注入到工作单元类型的类中,然后将其注入类中的实际查询(存储库或其他)中。如果您想深入研究这个主题,请查看this question。
https://stackoverflow.com/questions/55690339
复制相似问题