EF Core DbContext DI注入

把原来的MalemaDbContext改成下面的这个样子。我们希望这个数据库连接字符串,还有Provider都是由DI来控制的。

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

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

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 使用的时候都是用 IDbContextFactory dbContextFactory services.AddDbContext 和 services.AddDbContextPool 使用的时候都是用 MalemaDbContext dbContext

完整的代码在 https://gitee.com/malema/Examples/tree/dbcontext/di/EFCore-Example 可以用下面的git命令把代码签出到本地

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

var builder = new DbContextOptionsBuilder<MalemaDbContext>();
builder.UseSqlServer(connectionString);
var dbcontext = new MalemaDbContext(builder.Options);

单元测试这边也是这样实现的

最近更新的
...