[英]Dapper with .NET Core - injected SqlConnection lifetime/scope
I'm using .NET Core Dependency Injection to instantiate a SqlConnection
object during the application startup, which I'm then planning to inject in my repository.我正在使用 .NET Core Dependency Injection 在应用程序启动期间实例化
SqlConnection
对象,然后我计划将其注入到我的存储库中。 This SqlConnection
will be used by Dapper to read/write data from the database within my repository implementation. Dapper 将使用此
SqlConnection
从我的存储库实现中的数据库读取/写入数据。 I am going to use async
calls with Dapper.我将使用 Dapper 的
async
调用。
The question is: should I inject the SqlConnection
as transient or as a singleton?问题是:我应该将
SqlConnection
作为瞬态注入还是作为单例注入? Considering the fact that I want to use async
my thought would be to use transient unless Dapper implements some isolation containers internally and my singleton's scope will still be wrapped within whatever the scope Dapper uses internally.考虑到我想使用
async
这一事实,我的想法是使用瞬态,除非 Dapper 在内部实现了一些隔离容器,并且我的单例范围仍将被包裹在 Dapper 内部使用的任何范围内。
Are there any recommendations/best practices regarding the lifetime of the SqlConnection object when working with Dapper?使用 Dapper 时,是否有关于 SqlConnection 对象生命周期的任何建议/最佳实践? Are there any caveats I might be missing?
我可能会遗漏任何注意事项吗?
Thanks in advance.提前致谢。
If you provide SQL connection as singleton you won't be able to serve multiple requests at the same time unless you enable MARS, which also has it's limitations.如果您提供 SQL 连接作为单例,除非您启用 MARS,否则您将无法同时处理多个请求,这也有其局限性。 Best practice is to use transient SQL connection and ensure it is properly disposed.
最佳做法是使用瞬态 SQL 连接并确保正确处置它。
In my applications I pass custom IDbConnectionFactory
to repositories which is used to create connection inside using
statement.在我的应用程序中,我将自定义
IDbConnectionFactory
传递给存储库,该存储库用于在using
语句中创建连接。 In this case repository itself can be singleton to reduce allocations on heap.在这种情况下,存储库本身可以是单例的,以减少堆上的分配。
I agree with @Andrii Litvinov, both answer and comment.我同意@Andrii Litvinov 的回答和评论。
In this case I would go with approach of data-source specific connection factory.
在这种情况下,我将采用数据源特定连接工厂的方法。
With same approach, I am mentioning different way - UnitOfWork.使用相同的方法,我提到了不同的方式 - UnitOfWork。
Refer DalSession
and UnitOfWork
from this answer.从这个答案中参考
DalSession
和UnitOfWork
。 This handles connection.这处理连接。
Refer BaseDal
from this answer.从这个答案中参考
BaseDal
。 This is my implementation of Repository
(actually BaseRepository
).这是我的
Repository
实现(实际上是BaseRepository
)。
UnitOfWork
is injected as transient. UnitOfWork
作为瞬态注入。DalSession
for each data source.DalSession
来处理多个数据源。UnitOfWork
is injected in BaseDal
. UnitOfWork
注入BaseDal
。Are there any recommendations/best practices regarding the lifetime of the SqlConnection object when working with Dapper?
使用 Dapper 时,是否有关于 SqlConnection 对象生命周期的任何建议/最佳实践?
One thing most of developers agree is that, connection should be as short lived as possible.大多数开发人员同意的一件事是,连接应该尽可能短。 I see two approaches here:
我在这里看到两种方法:
using
block for each action.using
块中附上连接。 This is good approach as long as you do not want to group the actions.using
block here.using
块。 Solution is UnitOfWork as below.Great question, and already two great answers.很好的问题,已经有两个很好的答案。 I was puzzled by this at first, and came up with the following solution to solve the problem, which encapsulates the repositories in a manager.
一开始对这个很疑惑,想出了如下方案来解决这个问题,将repositories封装在一个manager中。 The manager itself is responsible for extracting the connection string and injecting it into the repositories.
管理器本身负责提取连接字符串并将其注入存储库。
I've found this approach to make testing the repositories individually, say in a mock console app, much simpler, and I've have much luck following this pattern on several larger-scale project.我发现这种方法可以单独测试存储库,比如在模拟控制台应用程序中,更简单,而且我在几个大型项目中遵循这种模式很幸运。 Though I am admittedly not an expert at testing, dependency injection, or well anything really!
虽然我承认我不是测试、依赖注入或任何其他方面的专家!
The main question I'm left asking myself, is whether the DbService should be a singleton or not.我要问自己的主要问题是 DbService 是否应该是单例。 My rationale was that, there wasn't much point constantly creating and destroying the various repositories encapsulated in
DbService
and since they are all stateless I didn't see much problem in allowing them to "live".我的理由是,不断创建和销毁封装在
DbService
的各种存储库并没有多大意义,而且由于它们都是无状态的,因此我认为允许它们“存活”并没有太大问题。 Though this could be entirely invalid logic.虽然这可能是完全无效的逻辑。
EDIT: Should you want a ready made solution check out my Dapper repository implementation on GitHub
编辑:如果你想要一个现成的解决方案,请查看我在GitHub 上的Dapper 存储库实现
The repository manager is structured as follows:存储库管理器的结构如下:
/*
* 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;
}
}
}
A sample repository would be structured as follows:示例存储库的结构如下:
/*
* 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
}
}
Wiring it all up:全部接线:
/*
* Startup.cs
*/
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//...rest of services
services.AddSingleton<IDbService, DbService>();
//...rest of services
}
And finally, using it:最后,使用它:
public SomeController : Controller
{
IDbService dbService;
public SomeController(IDbService dbService)
{
this.dbService = dbService;
}
public IActionResult Index()
{
return View(dbService.SomeRepo.List());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.