话题

嗯,距离上一次写博文已经过去近整整十个月,还是有一些思考,但还是变得懒惰了,心思也不再那么专注,有点耗费时间,学习也有点停滞不前,那就顺其自然,随心所欲吧,等哪天心血来潮,想写了就写写

模型自动更新方案研究(上)

一般团队人数很少时,使用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 模型自动更新(上)的更多相关文章

  1. EntityFrameworkCore 模型自动更新(下)

    话题 上一篇我们讨论到获取将要执行的迁移操作,到这一步为止,针对所有数据库都通用,在此之后需要生成SQL脚本对于不同数据库将有不同差异,我们一起来瞅一瞅 SQLite脚本生成差异 在上一篇拿到的迁移操 ...

  2. 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)

    1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...

  3. 艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)(一)

    艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输) 该系统基于开源的networkComms通讯框架,此通讯框架以前是收费的,目前已经免费并开元,作者是英国的,开发时间5年多,框架很稳定. 项 ...

  4. SVN----------项目服务器上的svn客户端自动更新设置。

    1.局域网服务器上搭建了PHP项目运行的环境,然后怎么样讲根目录拉去到的项目可以随着开发人员提交的代码,自动更新成最新的代码. 2.首先将svn版本库上的代码拉取到www目录下或者你的根目录. 3.然 ...

  5. .Net魔法堂:史上最全的ActiveX开发教程——自动更新、卸载篇

    一.前言 B/S模式的特点之一,客户端版本升级相对简单.快捷,适合产品的快速迭代.而ActiveX组件的自动更新同样也继承了这一优点.下面我们一起来了解吧! 二.二话不说更新ActiveX 1. 设置 ...

  6. ***git 本地提交后如果让服务器上的GIT 自动更新拉取

    Q: 最近配了个服务器,用的GIT,本地提交后服务器必须再拉取一下才能更新出来..求个提交后自动更新的方法 A: 最佳工具 git hook post-update.sample 改名为post-up ...

  7. EntityFrameworkCore使用Migrations自动更新数据库

    EntityFrameworkCore使用Migrations自动更新数据库 系统环境:Win10 IDE:VS2017 RC4 .netcore版本:1.1 一.新建ASP.NET Core Web ...

  8. iphone 屏蔽系统自动更新,消除设置上的小红点

    苹果ios系统的更新频率大家应该都知道,一般来说1个月就会来次更新.这一点让很多人讨厌.主要原因还是iPhone会自动下载更新包,然后一直不停地提示你是否安装更新,问题是我们还找不到关闭提醒和关闭自动 ...

  9. JSP通过AJAX获取服务端的时间,在页面上自动更新

    1.在页面上引入js <head> <meta http-equiv="Content-Type" content="text/html; charse ...

随机推荐

  1. RPA人力资源简历筛选机器人

    简历自动筛选及分析机器人,支持前程无忧.猎聘 1.自动登录招聘网站 2.自动填充简历筛选条件 3.RPA依次读取所筛选的简历信息 4.自动将简历数据复制到本地文档中 5.完成简历信息收集及分析表 6. ...

  2. 在docker中打开redis 客户端 cli

    首先交互方式进入redis容器 docker exec -it redis /bin/bash 随后运行客户端 redis-cli

  3. 异常概念&异常体系和异常分类

    异常概念 异常:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止. 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象.Java处 ...

  4. 从Wannacry到WannaRen:螣龙安科带你深度分析勒索病毒原理

    从Wannacry到WannaRen:螣龙安科2020年4月7日,360CERT监测发现网络上出现一款新型勒索病毒wannaRen,该勒索病毒会加密windows系统中几乎所有的文件,并且以.Wann ...

  5. Android刷第三方Recovery &获取root权限

    一.基础环境 Make sure your computer has working adb and fastboot. Setup instructions can be found here. E ...

  6. vue 调用nginx服务跨越的问题

    server { listen 80; server_name api.xxxx.com; add_header Access-Control-Allow-Origin '*' ; proxy_set ...

  7. mvc Ensure that HttpConfiguration.EnsureInitialized()

    The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called ...

  8. 动手实践丨手把手教你用STM32做一个智能鱼缸

    摘要:本文基于STM32单片机设计了一款基于物联网的智能鱼缸. 本文分享自华为云社区<基于STM32+华为云IOT设计的物联网鱼缸[玩转华为云]>,作者: DS小龙哥 . 1. 前言 为了 ...

  9. NOI / 2.1基本算法之枚举 1749:数字方格

    描述: 如上图,有3个方格,每个方格里面都有一个整数a1,a2,a3.已知0 <= a1, a2, a3 <= n,而且a1 + a2是2的倍数,a2 + a3是3的倍数, a1 + a2 ...

  10. dijkstra最短路算法(堆优化)

    这个算法不能处理负边情况,有负边,请转到Floyd算法或SPFA算法(SPFA不能处理负环,但能判断负环) SPFA(SLF优化):https://www.cnblogs.com/yifan0305/ ...