话题

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

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

一般团队人数很少时,使用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. Kali信息收集

    前言 渗透测试最重要的阶段之一就是信息收集,需要收集关于目标主机的基本细腻些.渗透测试人员得到的信息越多,渗透测试成功的概率也就越高. 一.枚举服务 1.1 DNS枚举工具DNSenum DNSenu ...

  2. KTL 一个支持C++14编辑公式的K线技术工具平台 - 第七版,体验GPGPU。

    K,K线,Candle蜡烛图. T,技术分析,工具平台 L,公式Language语言使用c++14,Lite小巧简易. 项目仓库:https://github.com/bbqz007/KTL 国内仓库 ...

  3. 基于mysql实现group by取各分组最新一条数据

    准备数据 SQL语句 SELECT * FROM admin WHERE id IN ( SELECT MAX( id ) FROM admin GROUP BY order_id ); 查询结果:

  4. 攻防世界进阶区MISC ——56-60

    56.low 得到一张bmp,世纪之吻,扔进kali中,binwalk,zsteg,无果,再放进stegsolve中,虽然发现小的数据块,但是过滤通道得不到任何信息,猜测是要用脚本进行 # lsb隐写 ...

  5. HashMap源码深度剖析,手把手带你分析每一行代码,包会!!!

    HashMap源码深度剖析,手把手带你分析每一行代码! 在前面的两篇文章哈希表的原理和200行代码带你写自己的HashMap(如果你阅读这篇文章感觉有点困难,可以先阅读这两篇文章)当中我们仔细谈到了哈 ...

  6. shell脚本函数及数组

    函数介绍: 函数function是由若干条shell命令组成的语句块,实现代码重用和模块话编程. 它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部 ...

  7. jdbc 09: preparedStatement实现增删改查

    jdbc连接mysql,利用preparedStatement实现增删改查 package com.examples.jdbc.o9_preparedStatement实现增删改; import ja ...

  8. jsx/tsx使用cssModule和typescript-plugin-css-modules

    目录 1,前言 2,效果图 3,如何使用 3.1,安装 3.2,配置 4,示例 5,插件错误处理 5.1,错误触发原因 5.2,解决办法 1,前言 在vite/webpack搭建的项目中,不管是vue ...

  9. 同时安装py2和py3-安装多版本python

    遇到问题和需求 我的电脑环境:先安装py2再安装py3,平时我工作中是使用python2,如何保证两个版本共存且让代码来选择要使用的版本. 遇到问题 在cmd中输入python,进入的是py2的环境, ...

  10. python3学习笔记之字符串

    字符串 1.一个个字符组成的有序的序列,是字符的集合: 2.使用单引号.双引号.三引号引住的字符序列 3.字符串是不可变对象 4.python3起,字符串就是Unicode类型: 字符串特殊举例: 不 ...