从 EFCore 开始,就推荐数据库根据实体由工具生成,即开发顺序为
建立实体——建立实体配置——建立DbContext——生成数据库
这样的顺序也称为 Code-First,即实体是比数据库先完成的。但假设我们的项目已经有数据了,这个时候如果要使用 EFCore,就需要从现有数据库生成实体,这个过程叫做 Reverse Engineering(反向工程)。
在 EF 里,也支持先建立数据库再生成实体的开发顺序,称为 Database-First,但这样的开发模式在 EFCore 中已经不被支持,在项目新增实体时,依然推荐使用 Code-First 模式进行开发。
下面介绍一下在 EFCore 里如何进行反向工程。
反向工程是通过 EFCore Tools 完成的,即在终端控制台执行 Scaffold-DbContext
命令,后面只需要接数据库连接字符串和数据库系统即可,以 SQLServer 为例:
Scaffold-DbContext "Data source=localhost;database=Test;Integrated Security=SSPI;" Microsoft.EntityFrameworkCore.SqlServer
执行后,EFCore 就会连接数据库,并根据数据库当前的设计生成实体,包括实体类文件、DbContext类文件等。这个命令是通过 Nuget 包名来指定数据库系统的。
通过反向工程生成的代码,都是按照既有约定的。例如 DbContext 类的名字为 <DatabaseName>Context,而实体类的名字是由表名生成的,例如 T_Books 会生成名为 TBook 的实体类。这个结果往往不是程序员想要的,这个时候可能需要手动修改使其符合规范。
并且反向工程生成的代码是没有创建单独的实体配置类的,而是将所有实体配置都写入 DbContext 中:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasAnnotation("Relational:Collation", "Chinese_PRC_CI_AS"); modelBuilder.Entity<TAuthor>(entity => { entity.ToTable("T_Authors"); }); modelBuilder.Entity<TBook>(entity => { entity.ToTable("T_Books"); entity.HasIndex(e => e.AuthorId, "IX_T_Books_AuthorId"); entity.Property(e => e.Title) .IsRequired() .HasMaxLength(50); });
如果实体很多,就可能导致 DbContext 代码混乱,相比独立的实体配置类来说不便管理。并且 EFCore 的反向工程并不具备 Migration 那样的版本更新或回滚功能,每一次 Scaffold-DbContext
命令都会从头开始生成实体,并可能覆盖之前生成的代码。所以反向工程最好只在必要的时候只使用一次,之后应该使用 Code-First 模式开发。