使用EF Core更新與修改生產資料庫

来源:https://www.cnblogs.com/podolski/archive/2022/10/08/16738842.html
-Advertisement-
Play Games

使用EF Core的Code First,在設計階段,直接使用Database.EnsureCreated()和EnsureDeleted()可以快速刪除、更新最新的數據結構。由於沒有什麼數據,刪除的風險非常低。但是對於已經投入生產的資料庫,這個方法就絕對不可行了。 考慮以下場景: 項目已經上線,一 ...


使用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下測試通過。

除非特殊說明,本作品由podolski創作,採用知識共用署名 4.0 國際許可協議進行許可。歡迎轉載,轉載請保留原文鏈接~喜歡的觀眾老爺們可以點下關註或者推薦~
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • class Person(object): def __init__(self): pass def info(self): print('我是person類中的info方法') 1.getattr()方法 這個方法是根據字元串去某個模塊中尋找方法 instantiation = reflect.P ...
  • 前言 無聊的時候做了一個搜索文章的軟體,有沒有更加的方便快捷不知道,好玩就行了 環境使用 Python 3.8 Pycharm 模塊使用 import requests import tkinter as tk from tkinter import ttk import webbrowser 最終 ...
  • 1 函數定義 1.1 函數概述 在程式設計中,函數的使用可以提升代碼的復用率和可維護性。 提升代碼的復用率: 程式設計中,一些代碼的功能是相同的,操作是一樣的,只不過針對的數據不一樣。此種情況下,可以將這種功能寫成一個函數模塊,要使用此功能時只需調用這個函數模塊就可以了。提升代碼的可維護性: 使用函 ...
  • 摘要:訪問者模式的目的是,解耦數據結構和演算法,使得系統能夠在不改變現有代碼結構的基礎上,為對象新增一種新的操作。 本文分享自華為雲社區《【Go實現】實踐GoF的23種設計模式:訪問者模式》,作者:元閏子 。 簡介 GoF 對訪問者模式(Visitor Pattern)的定義如下: Represent ...
  • 1.什麼是WebFlux? WebFlux不需要Servlet API,在完全非同步且無阻塞,並通過Reactor項目實現了Reactor Streams規範。 WebFlux可以在資源有限的情況下提高系統的吞吐量和伸縮性。 WebFlux除支持Restful Web服務外,還可以用於提供動態HTML ...
  • 作為軟體工程經理,我也會遇到人情世故的難題。最近一位團隊成員提出了離職申請,是因為個人的原因,而且很直接。 1、收到離職申請 我知道他會離職,我很少有措手不及的時候,所以我早就有預感,事實證明我的預感沒錯。幾周前,我就有一種感覺:“該來的遲早會來。”他們提出的問題、他們的疑慮以及他們有時會莫名離開辦 ...
  • 1.使用map()進行函數映射 ✅ Exp1:將字元串數組中的小寫字母轉為大寫字母。 測試數組為 oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']。 方法一 newlist = [] for word in oldlist: new ...
  • 1.需要保證電腦中安裝了protobuf安裝教程 2.如果出現報錯請看博客protobuf報錯問題解決 3.demo地址:demo 簡介: rpc微服務,grpc是一種開源的高性能RPC框架,能夠運行在任何環境中,最初由谷歌進行開發,它使用HTTP2作為傳輸協議。grpc讓客戶端可以像調用本地方法一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...