在ASP.NET CORE 3.1里使用MySql,ORM框架还是用微软的EF Core,code first,即先写好代码,再按代码(实体模型等)生成数据库,以下为学习笔记:
-
NuGet安装:Microsoft.EntityFrameworkCore包(3.1.10),然后MySql provider包这里有个坑,就是应使用Pomelo.EntityFrameworkCore.MySql(3.2.4),放弃MySql官方出的:MySql.Data.EntityFrameworkCore,官方的在修改实体模型(比如修改字段长度,改字段名等),使用命令Update-Database时会报错:The method or operation is not implemented,先安装这2个程序包;
-
新增实体模型并加一些特性,主要是主键约束、不允许为空、字符串长度、数据库表的字段类型等等;
public class Person
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(50)]
public string Email { get; set; }
[Required]
[Range(1, 100)]
public int Age { get; set; }
[Required]
[StringLength(11, MinimumLength=11)]
public string Phone { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal Salary { get; set; }
}
- 新建AppDbContext类(自定义名称)并继承自EF Core内置的Dbcontext基类,在构造函数里需传入DbcontextOption<>参数,并传给父类的构造函数;
public class AppDbContext:DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options):base(options)
{
}
}
- Startup.cs里注册AppDbContext(上面新增的dbcontext类)服务并初始化(主要是传入数据库链接字符串)等;
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); // webapi服务
services.AddDbContext<AppDbContext>(options => options.UseMySql(Configuration.GetConnectionString("MySql")));
}
// appsettings.json 里的数据库连接字符串
"ConnectionStrings": {
"MySql": "server=localhost; Database=Db; uid=root; pwd=123456;"
}
- 对于需要映射到数据库表的实体,设置为AppDbContex的DbSet<>属性;
public class AppDbContext:DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options):base(options)
{
}
public DbSet<Person> Person { get; set; }
}
- 创建空的数据库以及表结构;
- 方式主要是二种,基于Visual Studio带的包管理器的控制台(PMC)和基于命令行的dotnet ef命令;
- 基于Visual Studio带的包管理器的控制台(PMC):如果是Win电脑,则NuGet下载Microsoft.EntityFrameworkCore.Tools(3.1.10),这个包里有迁移命令,注意如果项目有分层,DbContext在一个独立的类库(DAL层或Repository层里)里的话,只需在这个DAL层类库里安装Microsoft.EntityFrameworkCore.Tools程序包,然后点开Package Manager Console(程序包管理控制台),在这里输入相关命令,以下假设项目有DAL层;
-
基于命令行的dotnet ef命令:如果不是Win电脑或者想在WIN电脑的CMD下使用数据库创建等相关命令,则需在CMD下执行命令:dotnet tool install --global dotnet-ef,这个工具从EF Core里独立出来了;
-
保存项目所有文件并执行生成解决方案(特别是实体模型文件、AppDbContext类等),编译没有问题后,在DAL层下打开PMC(程序包管理控制台)下执行命令:add-migration 自定义个命名(如果在CMD下执行:dotnet ef migrations add 自定义个命名);
-
此命令会搜索DBContext类下所有的DBSet以及对应的所有字段,然后和镜像文件比较,如果镜像文件不存在,则生成一个并把所有的表和字段都添加上,如果存在,则比较现有源码里的表结构和镜像文件的表结构的差异,把差异转换成增量文件,并更新镜像文件。这样就生成了迁移文件。注意先执行:生成解决方案,没问题后,再执行:add-migration;
-
执行命令后,会在DAL层生成迁移文件目录:Migrations 及相关代码,镜像文件(快照文件)就可以理解是数据库完整表结构的c#实现,有Snapshot字样的文件。而增量文件就是一堆AddColum,DropColumn,CreateTable,RemoveTable等函数,表示这次变化是添加了新字段,删除新字段等等增量操。
-
再执行:update-database(这个指令特别切换到CMD下执行,实现的功能与PMC一致),没有PMC的,比如mac电脑可以使用shell命令:dotnet ef database update,就在数据库里生成了空数据库及表结构,数据库中的_EFMigrationHistory表,就是数据库迁移历史表。此命令会连接数据库并查找__EFMigrationHistory表,根据里面的MigrationId,到当前的所有迁移增量文件里找,如果有对应的增量文件,则忽略,把没有在这个表里的所有增量文件执行一遍,通过AddColum,DropColumn,CreateTable,RemoveTable等函数来更新数据库。
-
后续修改、新增实体、修改AppDbContext等,重复执行add-migration 、update-database即可更新数据库;
-
AppDbContext里重写父类的方法:OnModuleCreating(),此方法可以设置实体模型在数据库里生成表时的一些的配置,还可以初始化数据库数据;
// 填充测试数据
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 填充测试数据,读取json格式的数据源,序列化成实体对象集合
string basePath = AppContext.BaseDirectory;
string filePath = Path.Combine(basePath, @"Modelsperson.json");
var personStr = File.ReadAllText(filePath);
var persons= JsonConvert.DeserializeObject<List<person>>(personStr );
modelBuilder.Entity<TouristRoute>().HasData(persons);
}
- 开发环境下SQL语句打印到控制台,需NuGet安装:
Microsoft.Extensions.Logging.Console
,在数据库上下文类(AppDbContext)里修改如下:
//SQL语句打印到控制台
private ILoggerFactory loggerFactory = LoggerFactory.Create(config =>
{
config.AddFilter((category, level) =>
{
//只打印 Information级别的以及数据库命令的
return category == DbLoggerCategory.Database.Command.Name &&
level == LogLevel.Information;
}
).AddConsole();
}
);
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLoggerFactory(loggerFactory);
}
EF Core migration分析
基于非源码的EFCore数据库迁移
ASP.NET CORE中使用EF CORE
EFCore + MySql codeFirst 迁移 Migration出现的问题