首页 > 数据库 >使用EF Core更新与修改生产数据库

使用EF Core更新与修改生产数据库

时间:2022-10-08 22:00:51浏览次数:93  
标签:Core 修改 数据库 EF migrationBuilder 使用

使用EF Core的Code First,在设计阶段,直接使用Database.EnsureCreated()EnsureDeleted()可以快速删除、更新最新的数据结构。由于没有什么数据,删除的风险非常低。但是对于已经投入生产的数据库,这个方法就绝对不可行了。

考虑以下场景:
项目已经上线,一直使用本地测试数据库进行开发,本地已经增加和修改了较多数据库表结构,线上数据庞大且实时更新,现在测试完毕需要进行上线。

如果需要更新生产数据库,我能想的有两种方法:

从一开始就使用Migration

从数据库开始设计的时候,就使用EF Migration,保证数据库能够与代码同步,不过操作的时候,需要极为小心,务必要检查生成的更新数据库代码,直接连接生产数据库,

需要注意的事项:

  • 从一开始就使用Migration任何时候都不要使用Context.Database.EnsureCreated或者EnsureDeleted语句。
  • 使用Add-migration之后,不要删除生成的Migration文件,这些文件记录了数据结构的变化历史。
  • 并不是所有的变化都能自动识别,比如“修改表列名称大小写”,这种情况很多时候生成的数据是执行删除然后再新建,和我们重命名的初衷相去甚远。因此要特别检查migrationBuilder.Drop相关的页面。

使用Scaffold

如果一开始就没有使用migration进行同步的话,那么使用EF Core将无法直接更新,我们需要变通一下:

逆向数据库到模型

首先需要数据库的数据结构逆向到模型,我们使用Scaffold就可以了,详细文档就可以查看这里,需要注意的是,我们的场景下,已经有修改好的DataContext与Model,在进行scaffold的过程中,一定要指定outputdir和context,不要和当前的文件冲突。

根据自己的喜好,选择是否采用-DataAnnotations,另外也可以使用-table指定需要修改的表,没有被指定的表,将保持原样。默认EF Core会按照自己的命名规则重新命名,如果你想保留自己的套路,那么使用-UseDatabaseNames参数。

Add-Migration

输出的模型我指定放在Models文件夹,原来的Models文件夹,我改成了Models1,并且更换了命名空间以保证项目现在能够正常编译。

  • 导出的模型与DbConext:Models.Models命名空间,Models文件夹
  • 新模型与DbConext:Models命名空间,Models1文件夹
    接下来运行Add-Migration
add-migration initialcreate -context exportedContext

这样会在Migrations文件夹下面生成一个snapshot和一个migration文件。snapshot是当前数据库的跟踪,另外一个是运用update-database时系统会执行的操作。里面有一个Up()和一个Down()方法,Up是执行更新时EF对数据库的操作,Down是回滚当前更改。由于这是第一次执行add-migration,EF Core会认为数据库现在还是空的,因此两个方法都有大量的语句,我们删除所有create和drop相关的语句,我这边是全部删除了,只留下空方法。

应用迁移,同步

前面准备工作已经到位了,这一步将直接操作数据库了。使用update-database将当前的migration更新到数据库,由于我们现在的数据结构和生产数据库的数据结构一模一样,实际上我们不需要执行什么操作(删除了Up、Down内部的代码),执行Update-Database只是让EF Core将Models和生产数据库建立联系

我理解只是添加__EFMigrationsHistory中的记录,以便EF Core后续追踪。

修改模型内容

将Models1中的文件覆盖Models中的文件,由于类型命名的差异,可能会提示一些错误,按照自己的习惯修改就好了。接下来是循序渐进,一点点修改模型,并经常add-migration,观察生成的语句是否正常。

由于我使用了Identity,在数据中有对应的AspNet开头的表,这些表我并不在本系统中使用(其他系统需要用),因此我删除了对应的模型、snapshot、DbContext记录,运行Add-Migration,生成了如下文件:

        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "AspNetRoleClaim");

            migrationBuilder.DropTable(
                name: "AspNetUserClaim");

            migrationBuilder.DropTable(
                name: "AspNetUserLogin");

            migrationBuilder.DropTable(
                name: "AspNetUserRoles");

            migrationBuilder.DropTable(
                name: "AspNetUserToken");

            migrationBuilder.DropTable(
                name: "AspNetRole");

            migrationBuilder.DropTable(
                name: "AspNetUser");
        }

说明现在已经能够正常跟踪我们的修改了,不过我这里需要保留对应的表,因此删除up与down的所有内容。

注意以下几点:

更新模型名称

如果使用fluentAPI,那么模型对应的表名称会直接在fluentAPI中直接指定,只修改模型的名称没有任何效果。修改的话,可以修改对应的fluentAPI,或者换用Annotation

提示找不到constraint

对于修改主键、索引等内容的情况,如果不是通过EF Core建立的数据库,那么命名规则可能不一样。对于postgresql数据库,可以用这个查询名称,然后修改对应的migration文件内容即可。

SELECT * FROM pg_CONSTRAINT

复合主键的限制

对于使用两列或者以上列作为复合主键的情况,使用EnsureCreated方法是可以识别Annotation形式的主键的。

[Key]
[Column(Order = 1)]
public string DeviceId { get; set; }
[Key]
[Column(Order = 2)]
public long Timestamp { get; set; }

使用Migration的时候,这种形式无法识别,需要在OnModelCreating()中,使用fluentAPI

modelBuilder.Entity<DeviceData>().HasKey(w => new { w.DeviceId, w.Timestamp });

Command执行超时

默认Command执行的超时设置只有30s,对一些大一点的表来说,是不太够的。可以设置:

optionsBuilder.UseNpgsql("Server=xxxxxxxxxxxxx", opt=>opt.CommandTimeout(3000));

增加命令执行的超时时间。

多个连接字符串的情况

如果程序使用了appsettings.Development.json之类的文件存储连接字符串,那么需要指定环境是Production(生产数据库),否则可能还原到本地数据库去了。
对于nuget包管理控制台(使用update-database),执行:

$Env:ASPNETCORE_ENVIRONMENT = "Development"
Update-Database

对于使用dotnet ef工具集的,直接执行:

dotnet ef database update --environment Development

cannot be cast automatically to type

设计数据库表如果修改列的数据类型(比如从varchar到integer),Postgresql会提示这个问题,导致无法修改。可以在migrationbuilder中使用sql,按照提示添加"USING "x"::integer"解决。但是这种方法还是不太优雅,手动处理Up()之后,还需要处理Down(),否则将无法正确还原。

可以使用分步的方法进行,假设我们需要将Id从varchar改成int4

  1. 添加一个字段temp,类型为int4,设置为[Key],然后删除Id字段。
  2. 添加并应用迁移
  3. 修改temp名称为Id
  4. 添加并应用迁移

多次应用迁移

每次修改尽量少一点,然后update-database,这样更容易发现问题,对于有

这种提示的,一定要检查生成语句中Drop相关的语句。

本地数据库与生产数据库,都有__EFMigrationsHistory记录相关的迁移情况。在生产与本地数据库中进行切换是,不用担心顺序问题,Update-Database会一个个应用迁移直到最新。

总结

使用Migration能够降低数据库同步中很多工作量,合理利用,可以对生产用的数据库进行热更新。

注:本文在.NET 6,EF Core 6下测试通过。

标签:Core,修改,数据库,EF,migrationBuilder,使用
From: https://www.cnblogs.com/podolski/p/16738842.html

相关文章

  • .NET Core和.NET Framework中DateTime.Now的区别
    今天和医院的微信公众号接口对接,需要传当前时间,我随手写了一个DateTime.Now传了过去,过了一会那边说时间格式不对,原来.NETCore中DateTime.Now的格式是2022/10/08下午04......
  • PriceFixed
    传送门题意:市场上有\(a[i]\)种商品,每种商品的价格都是\(2\)。现在你需要买这种商品\(a[i]\)件。但是对于第\(i\)种商品有一个属性\(bi\),意味着如果你已经买了\(bi......
  • 【Java基础】时间日期类之Date类、SimplDateFormat类、Calendar类及二月天案例
    目录​​一、Date类​​​​二、SimpleDateFormat类​​​​三、Calendar类​​​​四、二月天案例​​一、Date类Date代表一个特定的时间,精确到毫秒Date构造方法:方法名说明......
  • 案例分享:Qt工程机械真空激光焊接系统软件产品定制(西门子PLC,mysql数据库,用户权限控制,界
    需求  1.触摸屏控制,按照客户需求,ui由本司美工承担设计,显示分辨率1280x1024,同时支持鼠标操作。  2.权限控制:三种权限,分为管理员(可以定制模块界面,修改产品名称等定......
  • 快速部署瀚高数据库(保密)版本的方法
    背景公司这边有一套基于瀚高数据库的测试环境.因为重保期间调试比较麻烦.同事想让将其部署到不受限制的地方.本来想着进行一次备份恢复,然后响应的安装->设置->初始化......
  • proxy_cfw全局代理_浏览器代理配置(chromium based(edge)/firefox/IDM)
    文章目录​​无须sstap等软件实现虚拟网卡代理​​​​reference​​​​配置步骤​​​​serviceMode​​​​tunMode​​​​检查启用情况​​​​edge浏览器内部代理......
  • CentOS7安装.netCore
    CentOS7安装.NET之前,请运行以下命令,将Microsoft包签名密钥添加到受信任密钥列表,并添加Microsoft包存储库。打开终端并运行以下命令:sudorpm-Uvhhttps://packa......
  • 数据库设计
    约束约束:杜绝和限制不可能情况的数据非空约束默认约束外键约束数据库设计表关系多表查询内连接外连接......
  • Asp.Net Core Request生命周期
    官网文档有这么个图:返回的时候为什么还又反向走了各个MiddleWare的逻辑呢?所以按它这个图里的代码组织方式试了一下。图里的四个exeorder还真是以'next()'为为界,把一......
  • 数据库字段命名规范
    https://blog.csdn.net/qq_38188762/article/details/125725620三、数据库字段命名规范3.1字段命名规范(1)采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下......