多层项目中EFCore的使用 实体类:
1 2 3 4 5 6 7 public class Book { public long Id { get ; set; } public string Title { get; set; } public string AuthorName { get; set; } public double Price { get; set; } public DataSetDateTime PubDate { get; set; } }
配置类:
1 2 3 4 5 internal class BookConfig : IEntityTypeConfiguration<Book> { public void Configure(EntityTypeBuilder<Book> builder) { builder.ToTable("T_Books"); } }
设计思路 1、建立类库项目,放实体类、DbContext、配置类等。 DbContext中不配置数据库连接,而是为DbContext增加一个DbContextOptions类型的构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 public class MyDbContext:DbContext { public DbSet<Book> Books { get; set; } public MyDbContext(DbContextOptions<MyDbContext> options):base(options) { } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly (this.GetType().Assembly); } }
2、EFCore项目安装对应数据库的EFCore Provider。 3、asp.net core项目引用EFCore项目,并且通过AddDbContext来注入DbContext及对DbContext进行配置。
1 2 3 4 5 builder.Services.AddDbContext<MyDbContext>(opt => { string connStr = builder.Configuration.GetSection("ConnStr").Value; var serverVersion = new MySqlServerVersion(new Version(8, 0, 29)); opt.UseMySql(connStr, serverVersion); });
4、Controller中就可以注入DbContext类使用了。
1 2 3 4 5 6 7 8 9 10 11 12 13 [Route("api/[controller]/[action]")] [ApiController] public class TestController : ControllerBase { private readonly MyDbContext dbCtx; public TestController(MyDbContext dbCtx) { this.dbCtx = dbCtx; } [HttpGet] public string Deme1() { int c = dbCtx.Books.Count(); return $"C={c};"; } }
5、让开发环境的Add-Migration知道连接哪个数据库,在EFCore项目中创建一个实现了IDesignTimeDbContextFactory的类,并且在CreateDbContext返回一个连接开发数据库的DbContext。
1 2 3 4 5 6 7 8 9 10 internal class MyDbContextDesignFac : IDesignTimeDbContextFactory<MyDbContext> { public MyDbContext CreateDbContext(string[] args) { DbContextOptionsBuilder<MyDbContext> builder = new DbContextOptionsBuilder<MyDbContext>(); string connStr = "server=localhost;user=root;password=yourpassword;database=csharptest"; var serverVersion = new MySqlServerVersion(new Version(8, 0, 29)); builder.UseMySql(connStr, serverVersion); MyDbContext ctx = new MyDbContext(builder.Options); return ctx; } }
如果不在乎连接字符串被上传到Git,可以把连接字符串写死到CreatDbContext;如果在乎。那么CreateDbContext里面很难读取到vs中通过简单的方法设置的环境变量,所以必须把连接字符串配置到windows的正式的环境变量中,然后再Environment.GetEnvironmentVariable读取。 6、正常执行Add-Migration、Update-Database迁移就行了。需要把EFCore项目设置为启动项目,并且在【程序包管理器控制台】中也要选中EFCore项目,并且安装Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Tools
AddDbContextPool AddDbContext是Scope模式的依赖注入,当一个请求结束后就会销毁DbContext实例,在请求多的情况下会有一定的性能影响。 AddDbContextPool是池化技术,不用每次创建和销毁,会有一点性能提升
1 2 3 4 5 builder.Services.AddDbContextPool<MyDbContext>(opt => { string connStr = builder.Configuration.GetSection("ConnStr").Value; var serverVersion = new MySqlServerVersion(new Version(8, 0, 29)); opt.UseMySql(connStr, serverVersion); });
可能带来的问题: 1、AddDbContextPool注册的DbContext无法注入其他服务,因为这样注册的DbContext是Singleton的,在长生命周期的组件中无法注入短生命周期的组件,而大多数服务都不是Singleton的,所以可以理解成无法注入其他服务。 2、很多ADO.NET提供者都实现了数据库连接池机制,可能会有冲突,使用的时候需要自己调节。