C# 依赖注入 注入一个Func<DbContext>
在实际代码中有时候我们会希望每一次运行都需要一个新的对象, 比如EFCore当中的 DbContext。 因为DbContext有一些设计当中存在的问题。
- 跟踪对象,会导致性能越来越不好,
- SaveChanges 出错后会导致 后面的提交也会一直出错。(另一种处理方式是清掉错误)
- 某条记录在数据库被更改后,context因为有缓存住这个对象导致它的属性值不会发生变化. 所以取出来的数据还是旧的.
- 处理的函数中有Lock锁,DbContext却是一开始就注入的。这样会导致连接池不过用。
(该对象也不适合配置成Transient)
csharp
private static void Register(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IMessageWriter, MessageWriter>();
services.AddSingleton<Worker>();
//在这边注入 Func<MalemaDbContext>
services.AddSingleton(sp =>
{
var conn = configuration.GetConnectionString("malema");
return new Func<MalemaDbContext>(() =>
{
var builder = new DbContextOptionsBuilder<MalemaDbContext>();
builder.UseSqlServer(conn);
return new MalemaDbContext(builder.Options);
});
});
}使用它
csharp
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace Malema.net.Example
{
public class Worker
{
private readonly IMessageWriter _messageWriter;
private readonly Func<MalemaDbContext> _func;
public Worker(IMessageWriter messageWriter, Func<MalemaDbContext> func)
{
_messageWriter = messageWriter;
_func = func;
}
public async Task ExecuteAsync()
{
_messageWriter.Write($"Worker running at: {DateTimeOffset.Now}");
for(int i=0;i<10;i++)
{
//某些情况下我们希望dbContext每次都是不一样的
using (var dbContext = _func())
{
//
}
}
}
}
}通过使用 CreateScope() 我们也做到类似上面的效果. 详看 scope
Func<>这种方式可能不太好理解,更好理解的方式我们可以创建一个IMalemaDbContextFactory,这样它的注入方式就可以跟其它类一模一样了。
备注:实际上 EF5.0 之后有支持 IDbContextFactory<MalemaDbContext> 示例代码如下
csharp
var services = new ServiceCollection();
services.AddDbContextFactory<MalemaDbContext>(x => x.UseInMemoryDatabase("malema"));
//serviceCollection.AddPooledDbContextFactory<MalemaDbContext>(x => x.UseInMemoryDatabase("mlema"));//pool的方式
var factory = services.BuildServiceProvider().GetRequiredService<IDbContextFactory<MalemaDbContext>>();
using (var context = factory.CreateDbContext())
{
}