博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用 Entity Framework Core 时,通过代码自动 Migration
阅读量:4630 次
发布时间:2019-06-09

本文共 3775 字,大约阅读时间需要 12 分钟。

一 介绍

  在使用 Entity Framework Core (下面就叫 EF Core 吧)进行开发时,如果模型有变动,我们要在用 EF Core 提供的命令行工具进行手工迁移,然后再运行程序。但是为了效率,我想能不能在程序的入口处进行 Migration 呢?从个人经验来说应该是可以,因为 EF Tool 虽然提供了 CLI 但是它最终也是被程序解析这些命令。下面就开始分析,如何通过代码进行 Migration 。

二 分析

  首先我们要先了解,在使用 EF Core 的 CLI 时,要执行两个步骤:

    第一步:生成 Migration 文件;

    第二步:更新变更项到数据库;

  既然是先生成 Migration 文件再更新,那么在 EF Core 里面一定有对应的模块做这件事情。下面我们看一下 EF Core 项目的结构。从中我们确实找到关于 Migration 的模块。在 Migrations/Design 目录的类名称上我们可以看出来,它就是生成 Migration 文件的。这里先到这儿。

  

  找到了生成 Migration 文件的入口,我们再来找一下如何通过代码将这些变更更新到数据库中。

  在使用 EF Core 的时候,我们都要通过继承 DbContext 来编写自己的 DbContext 子类。在 DbContext 类中我们找到了一个 Database 属性。如下图所示:

  

  然后查看了 DatabaseFacde 这个类,并没有发现执行迁移相关的函数。通过代码搜索,我在 RelationalDatabaseFacadeExtensions 这个类中有一个 Migration() 扩展方法。通过注释的解析,我也确定了它就是执行 Migration 文件,并将变更更新到数据库。

  这两个步骤对应的代码我们都找到了,下面我们就编写一段儿代码,完成自动将模型变更更新到数据库的功能。

1 public class AutoMigration 2 { 3     private readonly IServiceProvider _serviceProvider; 4     private InformationDbContext _context; 5  6     public AutoMigration(IServiceProvider serviceProvider) 7     { 8         _serviceProvider = serviceProvider; 9         _context = serviceProvider.GetService
();10 }11 12 public void Migrator()13 {14 var path = Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\Migrations\\");15 if (!Directory.Exists(path))16 {17 Directory.CreateDirectory(path);18 }19 else20 {21 Directory.GetFiles(path).ToList().ForEach(File.Delete);22 }23 24 using (_context)25 {26 var services = ((IInfrastructure
) _context).Instance;27 var codeHelper = new CSharpHelper();28 var scaffolder = ActivatorUtilities.CreateInstance
(services,29 new CSharpMigrationsGenerator(codeHelper, new CSharpMigrationOperationGenerator(codeHelper),30 new CSharpSnapshotGenerator(codeHelper)));31 32 var projectDir = Path.Combine(path, "..\\");33 var migrationAssembly = new MigrationsAssembly(new CurrentDbContext(_context), _context.Options, new MigrationsIdGenerator());34 scaffolder.GetType().GetField("_migrationsAssembly", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(scaffolder, migrationAssembly);35 36 var readonlyDic = new ReadOnlyDictionary
(new Dictionary
());37 migrationAssembly.GetType().GetField("_migrations", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(migrationAssembly, new LazyRef
>(readonlyDic));38 var migration = scaffolder.ScaffoldMigration("Information.Migrations", "Information");39 40 scaffolder.Save(projectDir, migration, path);41 42 //另外一种保存方式43 //File.WriteAllText($"Migrations\\{migration.MigrationId}{migration.FileExtension}", migration.MigrationCode);44 //File.WriteAllText("Migrations\\" +45 // migration.MigrationId + ".Designer" + migration.FileExtension,46 // migration.MetadataCode);47 //File.WriteAllText("Migrations\\" + migration.SnapshotName + migration.FileExtension,48 // migration.SnapshotCode);49 }50 51 using(_context = (InformationDbContext)_serviceProvider.GetService
())52 {53 _context.Database.Migrate();54 }55 }56 }

  另外一个注意点:我们需要指定一下迁移文件所在项目。

1 services.AddDbContext
(opt =>2 {3 var connectionString = configuration["ConnectionStrings:DefaultConnection"];4 opt.UseSqlServer(connectionString, optionBuilder =>5 {6 optionBuilder.MigrationsAssembly("Information");7 });8 });

 

三 总结

  通过上面的分析可以知道,其实我们就是把 CLI 的两个命令通过代码实现了一下。在 Startup 文件中进行调用即可。为什么想这么干?因为在实际开发的时候,来回切换窗口心里觉得不爽了呗。:)

转载于:https://www.cnblogs.com/jRoger/p/entity-framework-core-auto-migration.html

你可能感兴趣的文章
delphi 一个时钟引发的事情
查看>>
JPEG和Variant的转换
查看>>
How to read very large text files fast
查看>>
Java读取.properties配置文件
查看>>
java绘制带姓的圆
查看>>
android数据的4种存储方式
查看>>
css缓存问题
查看>>
3dmax_FBX转havok_model
查看>>
Linux常用命令
查看>>
实验三 二叉树
查看>>
几种交叉验证(cross validation)方式的比较
查看>>
第44章:MongoDB-集群--Sharding(分片)--分片的片键选择
查看>>
自定义ISO结构
查看>>
7.11 animals.c 程序
查看>>
java Web三大组件--过滤器
查看>>
使用NUnit为游戏项目编写高质量单元测试的思考
查看>>
Uva 1638 Pole Arrangement
查看>>
Java内存泄漏
查看>>
逻辑函数的代数化简法
查看>>
第十一周PSP&进度条
查看>>