使用entityframeworkcore时,通过代码自动migration

杰子@ 杰子@     2022-08-03     155

关键词:

使用 Entity Framework Core 时,通过代码自动 Migration

一 介绍

  在使用 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<InformationDbContext>();
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         else
20         {
21             Directory.GetFiles(path).ToList().ForEach(File.Delete);
22         }
23 
24         using (_context)
25         {
26             var services = ((IInfrastructure<IServiceProvider>) _context).Instance;
27             var codeHelper = new CSharpHelper();
28             var scaffolder = ActivatorUtilities.CreateInstance<MigrationsScaffolder>(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<string,TypeInfo>(new Dictionary<string, TypeInfo>());
37             migrationAssembly.GetType().GetField("_migrations", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(migrationAssembly, new LazyRef<IReadOnlyDictionary<string, TypeInfo>>(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<IDbContext>())
52         {
53             _context.Database.Migrate();
54         }
55     }
56 }

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

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

 

三 总结

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

Microsoft.EntityFrameworkCore.Tools - 使用 .NET 5(隔离)设计时使用 HostBuilder 创建 DbContext 的 Azure Functions

】Microsoft.EntityFrameworkCore.Tools-使用.NET5(隔离)设计时使用HostBuilder创建DbContext的AzureFunctions【英文标题】:Microsoft.EntityFrameworkCore.Tools-AzureFunctionswith.NET5(Isolated)Design-timeDbContextCreationwithHostBuilder【发布时间】:2021 查看详情

aspnetcore2.0中entityframeworkcore及autofac的使用(附demo)((代码片段)

一,通过Entityframeworkcore中DbFirst模式创建模型这里只说一下Entityframeworkcore中DbFirst模式创建模型,想了解CodeFirst的可以自行度娘,还是在原有项目中创建一个Model类库,然后通过通过vs中NuGet的程序包管理控制台执行 安装EntityFr... 查看详情

一文学会使用entityframeworkcore(代码片段)

本文基于发稿时EFCore的最新版本5.0.文章目录1.操作篇2.原理篇3.优化篇4.常见问题4.1怎么查看生成的sql4.2怎么直接执行sql4.3怎么执行事务4.4怎么使用数据库锁4.4.1乐观锁4.4.2悲观锁4.5导航属性的类型4.6主外键的默认命名规则4.7EFCore... 查看详情

必看一文学会使用entityframeworkcore(代码片段)

本文基于发稿时EFCore的最新版本5.0.文章目录1.操作篇2.原理篇3.优化篇4.常见问题4.1怎么查看生成的sql4.2怎么直接执行sql4.3怎么执行事务4.4怎么使用数据库锁4.4.1乐观锁4.4.2悲观锁4.5导航属性的类型4.6主外键的默认命名规则4.7EFCore... 查看详情

C# Asp.Net EntityFrameworkCore 5.0 _ManageNav.cshtml.g.cs 在重建时使用语句删除

】C#Asp.NetEntityFrameworkCore5.0_ManageNav.cshtml.g.cs在重建时使用语句删除【英文标题】:C#Asp.NetEntityFrameworkCore5.0_ManageNav.cshtml.g.csdeletesusingstatementonrebuild【发布时间】:2022-01-1308:02:36【问题描述】:我正在使用entityframework5.0在asp.netMVC 查看详情

entityframeworkcore性能优化(代码片段)

https://docs.microsoft.com/zh-cn/ef/core/performance/文章目录1.定位性能问题1.1通过`LogTo`方法2.2将sql与LINQ查询关联起来2.解决问题3.进行Benchmark4.查询优化4.1正确使用索引4.2只查需要的属性4.3使用`Take`限制返回的条数4.4使用拆分... 查看详情

使用数据库优先方法时如何更新模型

...【发布时间】:2016-12-0823:02:33【问题描述】:我首先使用EntityFrameworkCore数据库创建模型asillustratedintheEFCoredocumentation但我不知道如何在编辑数据库后更新模型。【问题讨论】:它叫EntityFrameworkCore 查看详情

实体框架:更新具有 IEnumerable 属性的实体时出错。 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException'

】实体框架:更新具有IEnumerable属性的实体时出错。\\\'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException\\\'【英文标题】:EntityFramework:ErrorupdatinganEntitywithIEnumerableproperty.\'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyExcep 查看详情

无法解析 Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger 类型的服务

】无法解析Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger类型的服务【英文标题】:UnabletoresolveservicefortypeMicrosoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger【发布时间】:2022-01-1010:43:54【问题描述】:我在使用EF核心构建现有MySQL数... 查看详情

带有 EntityFrameworkCore 的 ASP.NET Core 中的 SQLite

】带有EntityFrameworkCore的ASP.NETCore中的SQLite【英文标题】:SQLiteinASP.NETCorewithEntityFrameworkCore【发布时间】:2016-07-2901:25:59【问题描述】:如何使用EntityFramework7在ASP.NETCoreWeb应用程序中添加和使用SQLite数据库?当我听说ASP.NETCore并创... 查看详情

如何使用 EntityFrameworkCore 定义父/子关系?

】如何使用EntityFrameworkCore定义父/子关系?【英文标题】:Howtodefineparent/childrenrelationwithEntityFrameworkCore?【发布时间】:2021-12-1202:42:12【问题描述】:我有一个项目使用EntityFrameworkCore来访问数据库中的数据。我正在尝试为单个对... 查看详情

运行所选代码生成器时出错:无法解析类型“Microsoft.EntityFrameworkCore.DbContextOption”的服务

】运行所选代码生成器时出错:无法解析类型“Microsoft.EntityFrameworkCore.DbContextOption”的服务【英文标题】:Therewasanerrorrunningtheselectedcodegenerator:Unabletoresolveservicefortype\'Microsoft.EntityFrameworkCore.DbContextOption【发布时间】:2021-10-0118: 查看详情

asp.netcore使用efcore(代码片段)

...目”>“管理NuGet程序包”查找安装sqlserver:Microsoft.EntityFrameworkCore.SqlServer:SqlServer数据库EF提供程序Microsoft.EntityFrameworkCore.Design:设计时使用到的EF共享库Microsoft.EntityFrameworkCore.Tools:EF的NuGet包管理器命令工具 M... 查看详情

我应该将啥 DbContext 与 EntityFrameworkCore 一起使用?

】我应该将啥DbContext与EntityFrameworkCore一起使用?【英文标题】:WhatDbContextshouldIusewithEnityFrameworkCore?我应该将什么DbContext与EntityFrameworkCore一起使用?【发布时间】:2019-04-1205:45:39【问题描述】:我有带有EFCore的.NetCore应用程序。... 查看详情

未创建 EntityFrameworkCore SQLite 内存数据库表

】未创建EntityFrameworkCoreSQLite内存数据库表【英文标题】:EntityFrameworkCoreSQLitein-memorydbtablesarenotcreated【发布时间】:2019-10-1215:36:02【问题描述】:对于集成测试,我正在使用EntityFrameworkCoreSQLite内存数据库并根据Microsoft文档创建其... 查看详情

在.netcore中如何让entityframeworkcore在日志中记录由linq生成的sql语句

...#xff0c;另一种方式是使用EFCore提供的日志。在ASP.NETCore使用EntityFrameworkCore的日志.早在EntityFrameworkCore1.0,使用相关的ILoggerProviderILogger这些基础接口类.来实现过日志记录.在EntityFrameworkCore2.0 估计是为了配合ASP.NETCore的日志.所以对这... 查看详情

EntityFrameworkCore.Sqlite - 如何使用包含给定列表的所有项目的子列表查询实体?

】EntityFrameworkCore.Sqlite-如何使用包含给定列表的所有项目的子列表查询实体?【英文标题】:EntityFrameworkCore.Sqlite-Howtoqueryentitieswithchildlistcontainingallitemsofgivenlist?【发布时间】:2022-01-0215:44:45【问题描述】:给定以下模型publicclass... 查看详情

通过 EF Core 自动创建时的默认 Azure SQL DB 定价

...布时间】:2019-11-2903:43:16【问题描述】:我们有一个使用EntityFrameworkCore的Web应用程序。如果给它一个连接到Azure上不存在的数据库的连接字符串,调用dbContext.Database.Migrat 查看详情