EntityFrameworkCore 模型自动更新(上)
话题
嗯,距离上一次写博文已经过去近整整十个月,还是有一些思考,但还是变得懒惰了,心思也不再那么专注,有点耗费时间,学习也有点停滞不前,那就顺其自然,随心所欲吧,等哪天心血来潮,想写了就写写
模型自动更新方案研究(上)
一般团队人数很少时,使用EF Core内置迁移基本已满足,满足的基本前提首先要生成迁移文件,然后和数据库进行对比,但团队人数一多,迁移文件等等涉及提交冲突等等,所以大部分情况下,我个人认为EF Core迁移基本没啥用,这玩意用不起来,尤其涉及到版本分支很多情况下,切换不同分支所使用的数据可能也会不同,我们常用MySql数据库,同时适配了人大金仓数据库、高斯数据库(GaussDb for opengauss),其对应的表结构有一些差异性,列类型也会有很大差异性,这对开发人员和测试人员来讲就是深深的折磨和痛苦,大部分时间会花在保持数据库表结构和模型一致,否则要么运行不起来,要么测试功能各种有问题,所以想想通过自动化方式来解决这个问题,本文还是分上下两篇写好了。
那么解决此问题的思路是怎样的呢?同时适配多套数据库,重写一套?那是不阔能的,既然我们可以通过dotnet ef命令来进行迁移,通过和数据库表结构进行对比,从而生成迁移文件,迁移文件包含即将要执行的差异性脚本,从这个角度来看的话,我们从迁移类反堆即可得到生成的脚本以及和数据库进行对比操作方法,初步设想理论上应该行得通,只需花时间了解下源码就好,通过前期两天的啃源码,最终啃出百把行代码即可自动更新模型到数据库,当然这个过程中还涉及一些要考虑的细节,我们一一再叙。接下来我们以MySql为例讲讲整个过程,其他数据库依葫芦画瓢就好,首先甩出如下代码:
var services = new ServiceCollection(); services.AddEntityFrameworkMySql(); services.AddEntityFrameworkDesignTimeServices(); services.AddDbContext<EfCoreDbContext>((serviceProvider, options) =>
{
options.UseInternalServiceProvider(serviceProvider); options.UseMySql("server=localhost;Port=3306;Database=test;Username=root;Password=root;",ServerVersion.AutoDetect("server=localhost;Port=3306;Database=test;Username=root;Password=root;"));
}); services.AddScoped<IDatabaseModelFactory, MySqlDatabaseModelFactory>(); var serviceProvider = services.BuildServiceProvider();
EF Core有属于它自己的容器,所以我们将全局容器和上下文所属容器做了区分,同时呢,我们将迁移中要用到的操作依赖也手动添加,比如上面的设计服务,存在于 Microsoft.EntityFrameworkCore.Design 包内,最后将获取数据库表结构模型工厂手动注入即MySqlDatabaseModelFactory。接下来我们要获取模型定义以及属性一些定义等等,也就是我们最终要生成的目标模型结构
using var scope = _serviceProvider.CreateScope(); var currentServiceProvider = scope.ServiceProvider; var context = (DbContext)currentServiceProvider.GetRequiredService<T>(); var connectionString = context.Database.GetDbConnection().ConnectionString; var targetModel = context.GetService<IDesignTimeModel>().Model.GetRelationalModel(); if (targetModel == null)
{
return Enumerable.Empty<MigrationOperation>().ToList();
}
接下来则是获取数据库表结构也就是数据库模型
var databaseFactory = currentServiceProvider.GetService<IDatabaseModelFactory>(); var factory = currentServiceProvider.GetService<IScaffoldingModelFactory>(); var tables = context.Model.GetEntityTypes().Select(e => e.GetTableName()).ToList(); if (!tables.Any())
{
return Enumerable.Empty<MigrationOperation>().ToList();
} // 仅查询当前上下文模型所映射表,否则比对数据库表差异时,将会删除非当前上下文所有表
var databaseModel = databaseFactory.Create(connectionString, new DatabaseModelFactoryOptions(tables: tables)); if (databaseModel == null)
{
return Enumerable.Empty<MigrationOperation>().ToList();
}
这里稍微需要注意的是,若是有多个不同上下文,肯定只查询当前上下文所对应的模型结构,不然最后生成的脚本会将其他上下文对应的表结构给删除。紧接着,我们需要将数据库模型转换为上下文中的模型,即类型一致转换,这就演变成了我们的源模型
var model = factory.Create(databaseModel, new ModelReverseEngineerOptions()); if (model == null)
{
return Enumerable.Empty<MigrationOperation>().ToList();
} var soureModel = model.GetRelationalModel();
接下来自热而然就进行源模型和目标模型差异性比对,得到实际要进行的迁移操作
var soureModel = model.GetRelationalModel(); //TODO Compare sourceModel vs targetModel var modelDiffer = context.GetService<IMigrationsModelDiffer>(); var migrationOperations = modelDiffer.GetDifferences(soureModel, targetModel);
那接下来问题来了,拿到差异性迁移操作后,我们应该怎么处理呢?留着各位思考下,我们下篇见
总结
本文给出了自动更新模型思路以及整个完整实现逻辑,剩余内容我们下篇再叙,主要是没心情写,写不下去了,今天我们就到此为止~
EntityFrameworkCore 模型自动更新(上)的更多相关文章
- EntityFrameworkCore 模型自动更新(下)
话题 上一篇我们讨论到获取将要执行的迁移操作,到这一步为止,针对所有数据库都通用,在此之后需要生成SQL脚本对于不同数据库将有不同差异,我们一起来瞅一瞅 SQLite脚本生成差异 在上一篇拿到的迁移操 ...
- 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)
1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...
- 艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)(一)
艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输) 该系统基于开源的networkComms通讯框架,此通讯框架以前是收费的,目前已经免费并开元,作者是英国的,开发时间5年多,框架很稳定. 项 ...
- SVN----------项目服务器上的svn客户端自动更新设置。
1.局域网服务器上搭建了PHP项目运行的环境,然后怎么样讲根目录拉去到的项目可以随着开发人员提交的代码,自动更新成最新的代码. 2.首先将svn版本库上的代码拉取到www目录下或者你的根目录. 3.然 ...
- .Net魔法堂:史上最全的ActiveX开发教程——自动更新、卸载篇
一.前言 B/S模式的特点之一,客户端版本升级相对简单.快捷,适合产品的快速迭代.而ActiveX组件的自动更新同样也继承了这一优点.下面我们一起来了解吧! 二.二话不说更新ActiveX 1. 设置 ...
- ***git 本地提交后如果让服务器上的GIT 自动更新拉取
Q: 最近配了个服务器,用的GIT,本地提交后服务器必须再拉取一下才能更新出来..求个提交后自动更新的方法 A: 最佳工具 git hook post-update.sample 改名为post-up ...
- EntityFrameworkCore使用Migrations自动更新数据库
EntityFrameworkCore使用Migrations自动更新数据库 系统环境:Win10 IDE:VS2017 RC4 .netcore版本:1.1 一.新建ASP.NET Core Web ...
- iphone 屏蔽系统自动更新,消除设置上的小红点
苹果ios系统的更新频率大家应该都知道,一般来说1个月就会来次更新.这一点让很多人讨厌.主要原因还是iPhone会自动下载更新包,然后一直不停地提示你是否安装更新,问题是我们还找不到关闭提醒和关闭自动 ...
- JSP通过AJAX获取服务端的时间,在页面上自动更新
1.在页面上引入js <head> <meta http-equiv="Content-Type" content="text/html; charse ...
随机推荐
- 一篇文章讲清楚MySQL的聚簇/联合/覆盖索引、回表、索引下推
迎面走来了你的面试官,身穿格子衫,挺着啤酒肚,发际线严重后移的中年男子. 手拿泡着枸杞的保温杯,胳膊夹着MacBook,MacBook上还贴着公司标语:"加班使我快乐". 面试官: ...
- 零基础学Python:元组(Tuple)详细教程
Python的元组与列表类似,不同之处在于元组的元素不能修改,元组使用小括号,列表使用方括号,元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可https://jq.qq.com/?_wv=1 ...
- centos7 yum error yum doesn't have enough cached data
1.vi /etc/resolv.conf,添加下面一行 nameserver 114.114.114.114 修改完成后service network restart进行重启,试一下yum upda ...
- C++实现ETW进行进程变动监控
C++实现ETW进行进程变动监控 文章地址:https://www.cnblogs.com/Icys/p/EtwProcess.html 何为Etw ETW(Event Tracing for Win ...
- linux Error downloading packages free 0 * needed 71 k
linux Error downloading packages free 0 * needed 71 k 原因:硬盘空间不足 查看磁盘大小 /]# df -hl 从/主目录开始搜索, ...
- MYSQL--安装2(命令行连接到数据库)
使用命令行窗口连接 MYSQL 数据库[操作示意图]
- 讲透JAVA Stream的collect用法与原理,远比你想象的更强大
大家好,又见面了. 在我前面的文章<吃透JAVA的Stream流操作,多年实践总结>中呢,对Stream的整体情况进行了细致全面的讲解,也大概介绍了下结果收集器Collectors的常见用 ...
- js基础学习-正则表达式
正则表达式用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具. 定义的方法: var patt = new RegExp(pattern, modifiers) // var patt ...
- python3学习笔记之字符串
字符串 1.一个个字符组成的有序的序列,是字符的集合: 2.使用单引号.双引号.三引号引住的字符序列 3.字符串是不可变对象 4.python3起,字符串就是Unicode类型: 字符串特殊举例: 不 ...
- 《Python编程:从入门到实践》第十八章笔记:Django最基本用法笔记
最近在看Python编程:从入门到实践,这是这本书"项目3 Web应用程序"第18章的笔记.记录了django最基本的一些日常用法,以便自己查阅. 可能是我的这本书版本比较老,书上 ...