EF Core DbContext DI注入
把原来的MalemaDbContext改成下面的这个样子。我们希望这个数据库连接字符串,还有Provider都是由DI来控制的。
csharp
using Microsoft.EntityFrameworkCore;
namespace Data
{
public class MalemaDbContext : DbContext
{
public MalemaDbContext(DbContextOptions<MalemaDbContext> options)
: base(options)
{
this.Database.EnsureCreated();
}
public DbSet<Student> Students { get; set; }
}
}创建一个使用DbContext的类 StudentService
csharp
using Data;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp
{
public class StudentService
{
private readonly MalemaDbContext dbContext;
private readonly IDbContextFactory<MalemaDbContext> dbContextFactory;
public StudentService(MalemaDbContext dbContext, IDbContextFactory<MalemaDbContext> dbContextFactory)
{
this.dbContext = dbContext;
this.dbContextFactory = dbContextFactory;
}
public void Add(Student student)
{
dbContext.Add(student);
dbContext.SaveChanges();
}
public void Add2(Student student)
{
//可以看到我们这边用的是 dbContextFactory创建出来的。 这样的功能是很用的。
//在一些后台任务当中,我们希望每一次的任务,都是一个全新DbContext。
//我们的这个StudentService就可以被注册成单例
using (var dbContext = dbContextFactory.CreateDbContext())
{
dbContext.Add(student);
dbContext.SaveChanges();
}
}
}
}注入DbContext,DbContextFactory, 或者 池化版的 DbContextPool, PooledDbContextFactory
csharp
using Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var sp = GetSserviceProvider();
var studentService = sp.GetService<StudentService>();
studentService.Add(new Student() { Name = "abc" });
studentService.Add2(new Student() { Name = "abc2" });
}
private static ServiceProvider GetSserviceProvider()
{
var connectionString = "Data Source=127.0.0.1;Initial Catalog=MalemaEFCoreExample;Persist Security Info=True;User Id=sa;Password=malema987%^&";
var optionBuilder = new DbContextOptionsBuilder<MalemaDbContext>();
optionBuilder.UseSqlServer(connectionString);
var services = new ServiceCollection();
// services.AddDbContext<MalemaDbContext>(options => options.UseSqlServer(connectionString)); //注入DbContext
// services.AddDbContextFactory<MalemaDbContext>(options => options.UseSqlServer(connectionString)); // 注入 DbContext factory
services.AddDbContextPool<MalemaDbContext>(options => options.UseSqlServer(connectionString), poolSize: 64); //注入 DbContext 池
// 注入 DbContext factory 来从池中生成 Dbcontext
services.AddPooledDbContextFactory<MalemaDbContext>(options => options.UseSqlServer(connectionString), poolSize: 64);
services.AddScoped<StudentService, StudentService>();
var sp = services.BuildServiceProvider();
return sp;
}
}
}使用 DbContext池,在性能上可以获得一些提升。 services.AddDbContextFactory 和 services.AddPooledDbContextFactory<MalemaDbContext> 使用的时候都是用 IDbContextFactory<MalemaDbContext> dbContextFactory services.AddDbContext<MalemaDbContext> 和 services.AddDbContextPool<MalemaDbContext> 使用的时候都是用 MalemaDbContext dbContext
完整的代码在 https://gitee.com/malema/Examples/tree/dbcontext/di/EFCore-Example 可以用下面的git命令把代码签出到本地
powershell
git clone https://gitee.com/malema/Examples
git checkout dbcontext/di更改 SqlConnection池的大小
在使用池的时候有一个要注意的事项。SqlConnection默认池大小是 100,小于 DbContext池的默认值128. 所以在注入的时候我们需要配置一个更小的值。或者我们得去更改我们的数据库连接字符串 在上面的字符串里面加上;Max Pool Size=1024;Pooling=true; Pooling是默认开启的可以不管它。
如何new一个DbContextOptions
使用DbContextOptionsBuilder
csharp
var builder = new DbContextOptionsBuilder<MalemaDbContext>();
builder.UseSqlServer(connectionString);
var dbcontext = new MalemaDbContext(builder.Options);<a href="https://www.malema.net/csharp-unit-test/mocks/mock-dbcontext.html">单元测试</a>这边也是这样实现的
