<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          在生產(chǎn)環(huán)境下處理EFCore數(shù)據(jù)庫遷移的五種方法

          共 9221字,需瀏覽 19分鐘

           ·

          2020-08-19 06:08

          在生產(chǎn)環(huán)境下處理EFCore數(shù)據(jù)庫遷移的五種方法

          原文鏈接:https://www.thereformedprogrammer.net/handling-entity-framework-core-database-migrations-in-production-part-1/

          作者:Jon P Smith,是《?Entity Framework Core in Action》的作者

          安德魯·洛克(Andrew Lock)撰寫了精彩的系列文章《在ASP.NET Core中的應用程序啟動時運行異步任務》,其中他以“遷移數(shù)據(jù)庫”為例,介紹了您可以在啟動時執(zhí)行的操作。

          在他該系列的第3部分中,他介紹了為什么在啟動時遷移數(shù)據(jù)庫并不總是最佳選擇。我決定編寫一系列有關可以安全遷移數(shù)據(jù)庫的不同方法的系列文章,即使用Entity Framework Core(EF Core)更改數(shù)據(jù)庫的架構。

          這是本系列的第一部分,介紹如何創(chuàng)建遷移,而第二部分則介紹如何將遷移應用于數(shù)據(jù)庫,特別是生產(chǎn)數(shù)據(jù)庫。在撰寫本文時,我使用了與安德魯類似的方法,即,我嘗試使用EF Core的優(yōu)點和缺點,一路介紹創(chuàng)建遷移腳本的所有方式。

          注意:Andrew和我彼此認識,因為我們同時在為Manning Publications撰寫書籍:Andrew的書是“ ASP.NET Core in Action,而我寫的書是“ Entity Framework Core in Action ”。我們分享了當作家的辛勞和喜悅,但是安德魯在ASP.NET Core方面的工作更加艱辛–他的書長700頁,而我的書“只有” 500頁。

          TL; DR –創(chuàng)建遷移的摘要

          注意:單擊鏈接可直接轉到涵蓋該點的部分。

          ?可以將兩種類型的遷移應用于數(shù)據(jù)庫:?添加新的表,列等,稱為不間斷的更改(簡單)。?更改列/表并需要復制數(shù)據(jù),稱為重大更改(困難)。?有五種方法可以在EF Core中創(chuàng)建遷移?使用EF Core創(chuàng)建遷移-簡單,但不能處理所有可能的遷移。?使用EF Core創(chuàng)建遷移,然后手動修改遷移-中到難,但處理所有可能的遷移。?使用第三方遷移構建器來編寫C#遷移-很難,因為您需要自己編寫遷移,但是您不需要了解SQL。?使用SQL數(shù)據(jù)庫比較工具比較數(shù)據(jù)庫并輸出SQL更改腳本–很簡單,但是您確實需要對SQL有一定的了解。?通過復制EF Core的SQL來編寫自己的SQL遷移腳本 –很難理解,可以很好地控制,但您確實需要了解SQL。?如何確保您的遷移有效–使用CompareEfSql工具。

          場景–關于創(chuàng)建遷移,我們應該問什么問題?

          有很多遷移數(shù)據(jù)庫模式的方法,在開發(fā)中,幾乎可以使用任何方法。但是,當涉及到遷移生產(chǎn)數(shù)據(jù)庫(即實際用戶正在使用的數(shù)據(jù)庫)時,它就變得非常嚴重。弄錯了,至少會給您的用戶帶來不便,并且更糟的是,甚至會丟失您數(shù)據(jù)庫中的(寶貴)數(shù)據(jù)!

          在獲得更新數(shù)據(jù)庫模式部分之前,我們需要構建遷移腳本,該腳本將包含模式以及可能的數(shù)據(jù)更改。要構建適當?shù)倪w移腳本,我們需要問自己一些有關需要應用到數(shù)據(jù)庫的更改類型的重要問題。所需的遷移將是:

          1.一個非重大更改,也就是說,它只是增加了新的欄目,表格等,這可能而舊的軟件仍然運行應用,即舊的軟件將與遷移后的數(shù)據(jù)庫一起運行。2.一個重大更改,即有些數(shù)據(jù)必須復制或遷移過程中轉化,無法應用,而舊的軟件,即舊的軟件會遇到與遷移后的數(shù)據(jù)庫錯誤(中斷服務)。

          本文中也介紹了我們正在使用EF Core,它帶來的一些好處和限制。好處是,在大多數(shù)情況下,EF Core可以自動創(chuàng)建所需的遷移。

          約束條件是應用遷移后的數(shù)據(jù)庫必須與EF Core通過查看您的DbContext和映射的類建立的數(shù)據(jù)庫軟件模型匹配–我指的是帶有大寫M的EF Core模型,因為存在一個名為DbContext中的模型,其中包含類和數(shù)據(jù)庫之間的完整映射。

          注意:我將介紹遷移,在這些遷移中,您可以控制映射到數(shù)據(jù)庫的類的控制和EF Core配置-有時也稱為代碼優(yōu)先方法。

          我不會介紹另一種替代方法是,您直接控制數(shù)據(jù)庫,并使用稱為 scaffolding的EF Core命令為您創(chuàng)建實體類和EF Core配置。采用這種方法遷移很簡單–只需重新搭建數(shù)據(jù)庫即可。

          第1部分,創(chuàng)建遷移腳本的五種方法

          正如我在上一節(jié)中所述,我們創(chuàng)建的任何遷移腳本都必須將數(shù)據(jù)庫遷移到與EF Core Model匹配的狀態(tài)。例如,如果遷移在表中添加了新列,則映射到該表的實體類必須具有與該新列匹配的屬性。如果數(shù)據(jù)庫架構的EF Core的模型確實與數(shù)據(jù)庫匹配,則您可能會在查詢或寫入中發(fā)生錯誤。如果遷移腳本與該數(shù)據(jù)庫的EF Core模型匹配,則將其稱為創(chuàng)建“可用”數(shù)據(jù)庫。

          毫無疑問,EF Core創(chuàng)建的遷移的有效性– EF Core創(chuàng)建了它,因此它將是有效的。但是,如果我們需要編輯遷移,或者我們自己進行遷移構建,那么我們需要非常小心,就EF Core而言,遷移會創(chuàng)建一個“可用”數(shù)據(jù)庫。這是我考慮過很多的事情。

          這是創(chuàng)建遷移腳本的方法的列表。

          ?創(chuàng)建C#遷移腳本1.標準EF Core遷移腳本:使用EF Core的Add-Migration命令創(chuàng)建C#遷移腳本。2.手動修改的EF Core遷移腳本:使用EF Core的Add-Migration命令創(chuàng)建C#遷移腳本,然后對其進行手動編輯以添加EF Core遺漏的位。3.使用第三方遷移構建器,例如FluentMigrator。這樣的工具使您可以用C#編寫自己的遷移腳本。?創(chuàng)建SQL遷移腳本。1.使用SQL數(shù)據(jù)庫比較工具。它將最后一個數(shù)據(jù)庫架構與EF Core創(chuàng)建的新數(shù)據(jù)庫架構進行比較,并生成一個SQL腳本,該腳本會將舊數(shù)據(jù)庫遷移到新數(shù)據(jù)庫架構。2.編寫自己的SQL遷移腳本。稱職的SQL編寫者可以通過捕獲SQL EF Core用來創(chuàng)建數(shù)據(jù)庫的方式來編寫SQL遷移腳本。

          這是一個摘要圖,可讓您對這五種方法進行總體回顧,并就其易用性和局限性提出個人看法。

          [1]


          現(xiàn)在,讓我們依次看一看。

          1a,標準EF Core C#遷移腳本

          這是EF Core提供的標準遷移技術。Microsoft官方文檔中提供了充分的文檔記錄[2],總而言之,您運行了一個名為Add-Migration的命令,該命令將三個C#文件添加到您的應用程序,其中包含使用Add-Migration 遷移現(xiàn)有數(shù)據(jù)庫以匹配當前EF Core設置/配置所需的更改。

          好處·自動構建遷移 ·無需學習SQL ·包括還原遷移功能
          壞處
          局限性標準遷移無法處理重大更改(但請參見1b)。不處理SQL功能,例如SQL用戶定義的函數(shù)(但請參見1b)。
          提示運行“添加遷移”方法時請注意錯誤消息。如果EF Core檢測到可能丟失數(shù)據(jù)的更改,它將輸出一條錯誤消息,但仍會創(chuàng)建遷移文件。您必須更改遷移腳本,否則將丟失數(shù)據(jù)–請參閱第1b節(jié)。·如果您的DbContext在另一個注冊了DbContext的程序集中,則需要在構建中使用MigrationsAssembly方法,并且很可能需要在DbContext程序集中實現(xiàn)IDesignTimeDbContextFactory。
          結論這是處理遷移的一種非常簡單的方法,并且在許多情況下效果很好。問題是,如果遷移無法滿足您的需求,將會發(fā)生什么情況。幸運的是,有很多方法可以解決這個問題。

          參考:Microsoft的有關創(chuàng)建遷移的文檔[3]

          1b,手工修改的EF Core C#遷移腳本

          關于EF Core的Add-Migration命令的好處是,它以C#遷移文件為起點,但是您可以自己編輯這些文件以添加代碼來處理重大更改或添加/更新數(shù)據(jù)庫的SQL部分。Microsoft提供了通過復制數(shù)據(jù)處理重大更改的示例。

          好處與標準遷移相同+ ·能夠自定義遷移。·能夠包含SQL功能,例如SQL用戶定義的功能。
          壞處·您需要了解數(shù)據(jù)庫中正在隱藏的內(nèi)容。·可能難以決定如何編輯文件,例如,您是否保留了EF Core的所有內(nèi)容,然后對其進行了更改,還是刪除了EF Core部件并自己完成了?
          局限性沒有簡單的方法來檢查遷移是否正確(但請參閱稍后的CompareEfSql)。
          提示與標準遷移相同。
          結論非常適合進行較小的更改,但由于經(jīng)常將C#命令與SQL混合使用,因此進行較大的更改可能很困難。這就是為什么我不使用EF Core遷移的原因之一。

          參考:Microsoft手動修改遷移的示例[4]

          1c.使用第三方C#遷移構建器

          安德魯·洛克(Andrew Lock)向我指出了一種使用FluentMigrator編寫遷移的方法。這與EF遷移的工作原理類似,但是您必須完成詳細說明更改的所有艱苦工作。好消息是FluentMigrator的命令非常明顯。

          好處不需要學習SQL。能明顯的看到更改了什么,即“代碼作為文檔”。
          壞處·您必須確定自己所做的更改。不保證產(chǎn)生“正確的”遷移(但請參閱稍后的CompareEfSql)。
          局限性- 沒有 -
          提示請注意,F(xiàn)luentMigrator有一個“ Migration Runners”,可以將更新應用于數(shù)據(jù)庫,但也可以輸出SQL腳本。
          結論我自己沒有真正的經(jīng)驗。感覺這是EF Core遷移的一種更清晰的語法,但是您必須自己完成所有工作。

          參考:GitHub的FluentMigrator[5]

          2a.使用SQL數(shù)據(jù)庫比較工具


          有免費的和商業(yè)的工具可以比較兩個數(shù)據(jù)庫并創(chuàng)建一個SQL更改腳本,該腳本將舊數(shù)據(jù)庫架構遷移到新數(shù)據(jù)庫架構。

          Visual Studio 2017(所有版本)中的“視圖”選項卡下內(nèi)置了一個名為“SQL Server Object Explorer”的“免費”比較工具。如果右鍵單擊數(shù)據(jù)庫,則可以訪問“比較模式”工具(請參見右圖),該工具可以生成SQL更改腳本。

          SQL Server的對象資源管理器工具是非常好的,但是沒有(可惜)多文檔。其他商業(yè)系統(tǒng)包括Redgate的SQL Compare。


          好處為您構建正確的SQL遷移腳本。
          壞處·您需要對數(shù)據(jù)庫有一點了解。·并非所有的SQL比較工具都生成還原腳本。
          局限性不處理重大更改-需要人工輸入。
          提示請注意SQL比較工具,該工具可以輸出日光下的所有設置,以確保設置正確。EF Core的遷移非常簡單,例如“ CREATE TABLE…”,因此應該這樣做。如果您有任何特定設置,則將它們構建到數(shù)據(jù)庫create中。
          結論我在難以手動編碼的大型遷移中使用了SQL Server對象資源管理器。對不熟悉SQL語言的人非常有用,尤其有用。

          2b.手工編碼SQL遷移腳本

          這聽起來確實很困難-編寫自己的SQL遷移,但是手頭上有很多幫助,無論是來自SQL比較工具(參見上文),還是查看SQL EF Core用于創(chuàng)建數(shù)據(jù)庫的幫助。這意味著我可以查看并復制以構建結論SQL遷移腳本的SQL。

          好處完全控制數(shù)據(jù)庫結構,包括EF Core不會添加的部分,例如用戶定義的函數(shù),列約束等。
          壞處·您必須了解基本的SQL,如CREATE TABLE等。·您必須確定自己所做的更改(但有幫助) ·不能進行自動還原遷移。·不保證產(chǎn)生“正確的”遷移(但請參閱稍后的CompareEfSql)。
          局限性- 沒有 -
          提示·我使用一個單元測試來捕獲EF Core的確保創(chuàng)建方法的日志輸出。那讓我得到了實際的SQL EF Core輸出。然后,我尋找最后一個數(shù)據(jù)庫的差異。這使得編寫SQL遷移更加容易。? ?·通過應用所有遷移(包括新遷移)創(chuàng)建數(shù)據(jù)庫,然后運行CompareEfSql來檢查數(shù)據(jù)庫是否與EF Core的當前數(shù)據(jù)庫模型匹配,從而對遷移進行單元測試。
          結論這是我使用的,在CompareEfSql工具的幫助下。如果EF Core的遷移功能非常好,為什么還要處理所有這些麻煩呢?這是結論原因:·完全控制數(shù)據(jù)庫結構,包括EF Core不會添加的部分,例如用戶定義的函數(shù),列約束等。·由于我正在編寫SQL,因此使我考慮了數(shù)據(jù)庫的各個方面。更改–該屬性是否可以為空?我需要索引嗎?等 ·通過手動修改EF Core的遷移系統(tǒng)來應對重大變化并非易事。我還是堅持使用SQL遷移。這是針對想要完全控制和可視化遷移的開發(fā)人員的。

          您可以捕獲EF Core的SQL輸出以創(chuàng)建數(shù)據(jù)庫,但是可以在調(diào)用方法 EnsureCreated ( EnsureCreated 方法用于創(chuàng)建單元測試數(shù)據(jù)庫)時捕獲EF Core的日志記錄。因為為EF Core設置日志記錄有些復雜,所以我在EfCore.TestSupport庫中添加了輔助方法來處理該問題。這是一個示例單元測試,它創(chuàng)建一個新的SQL數(shù)據(jù)庫并捕獲EF Core生成的SQL命令。

          [RunnableInDebugOnly]publicvoidCaptureSqlEfCoreCreatesDatabaseToConsole(){//SETUPvar options = this.CreateUniqueClassOptionsWithLogging<BookContext>(        log => _output.WriteLine(log.Message));using(var context = newBookContext(options)){
          //ATTEMPT context.Database.EnsureDeleted(); context.Database.EnsureCreated();}}

          讓我們看一下這段代碼的每一行

          ?第5行。這是一個EfCore.TestSupport方法,為您的DbContext創(chuàng)建選項。此版本使用包含類名的數(shù)據(jù)庫名稱。我這樣做是因為xUnit測試類是并行運行的,所以我想要此單元測試類的唯一數(shù)據(jù)庫。?第6行。我使用以... WithLogging結尾的選項生成器的版本,該版本允許我捕獲日志輸出。在這種情況下,我將日志的Message部分直接輸出到單元測試輸出窗口。?第11和12行。首先,我確保刪除數(shù)據(jù)庫,以便在我調(diào)用確保創(chuàng)建時,將使用由當前DbContext的配置和映射的類定義的架構來創(chuàng)建一個新的數(shù)據(jù)庫。

          以下是在單元測試輸出中捕獲的部分輸出。這為您提供了EF Core用于創(chuàng)建整個架構的確切SQL。您確實只需要提取與遷移有關的部分,但是至少您可以將所需的部分剪切并粘貼到SQL遷移腳本中。

          CREATE DATABASE [EfCore.TestSupport-Test_TestEfLogging];ExecutedDbCommand(52ms) [Parameters=[], CommandType='Text', CommandTimeout='60']IF SERVERPROPERTY('EngineEdition') <> 5BEGIN    ALTER DATABASE [EfCore.TestSupport-Test_TestEfLogging] SET READ_COMMITTED_SNAPSHOT ON;END;ExecutedDbCommand(5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']CREATE TABLE [Authors] ([AuthorId] int NOT NULL IDENTITY,[Name] nvarchar(100) NOT NULL,    CONSTRAINT [PK_Authors] PRIMARY KEY ([AuthorId]));ExecutedDbCommand(1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']CREATE TABLE [Books] ([BookId] int NOT NULL IDENTITY,[Title] nvarchar(256) NOT NULL,-- rest of SQL left out

          如何確保您的遷移有效–使用CompareEfSql工具

          在創(chuàng)建遷移的描述中,我曾多次提到CompareEfSql。該工具將數(shù)據(jù)庫與EF Core首次用于DbContext時創(chuàng)建的數(shù)據(jù)庫模型進行比較。通過DbContext實例中的Model屬性訪問此模型,是通過查看DbContext配置以及DbSet和DbQuery屬性來構建結論EF Core的。

          這使開發(fā)人員可以根據(jù)EF Core Model測試現(xiàn)有數(shù)據(jù)庫,并在錯誤消息不同的情況下為您提供錯誤消息。我發(fā)現(xiàn)這是一個非常強大的工具,它使我可以手動編碼SQL遷移,并確保它們是正確的有一些小限制。這是一個示例單元測試,如果數(shù)據(jù)庫架構與EF Core的模型不匹配,該測試將失敗。

          [Fact]publicvoidCompareViaContext(){//SETUPvar options = … options that point to the database to check;using(var context = newBookContext(options)){var comparer = newCompareEfSql();
          //ATTEMPT//This will compare EF Core model of the database //with the database that the context's connection points tovar hasErrors = comparer.CompareEfWithDb(context);
          //VERIFY//The CompareEfWithDb method returns true if there were errors.//The comparer.GetAllErrors property returns a string//where each error is on a separate line hasErrors.ShouldBeFalse(comparer.GetAllErrors);}}

          我喜歡這個工具,它位于EFCore.TestSupport開源庫中。它使我能夠構建遷移,并確保它們能夠正常工作。我也將其作為正常的單元測試來運行,它會立即告訴我是否是我或另一個同事更改了EF Core的設置。

          您可以在名為EF Core的文章中獲得對該工具的更詳細的描述:完全控制數(shù)據(jù)庫模式及其許多功能和配置可以在CompareEfSql文檔頁面中找到[7]

          注意:我最初是為EF6.x構建此版本的(請參閱此舊文章),但是由于EF6.x并未完全公開其內(nèi)部模型而受到限制。

          有了EF Core,我可以做更多的事情,現(xiàn)在我可以檢查幾乎所有內(nèi)容,并且因為我利用了EF Core的腳手架服務,所以它適用于EF Core支持的任何數(shù)據(jù)庫。

          結論–第1部分

          本系列的這一部分將介紹如何創(chuàng)建有效的遷移,而第二部分則涉及將遷移應用于數(shù)據(jù)庫。本文列出了使用EF Core時用于創(chuàng)建數(shù)據(jù)庫遷移的所有適用方法-優(yōu)缺點。如您所見,EF Core的Add-Migration命令確實很好,但是并不能涵蓋所有情況。

          由您決定要遇到的遷移類型,以及您希望對數(shù)據(jù)庫架構進行何種級別的控制。如果您僅使用EF Core的標準遷移(1a)就可以擺脫困境,那么這將使您的生活更輕松。但是,如果您預期會發(fā)生重大變化,或者需要設置額外的SQL功能,那么您現(xiàn)在知道可用的選項。

          令人擔心的部分出現(xiàn)在part2中-將遷移應用于生產(chǎn)數(shù)據(jù)庫。更改包含關鍵業(yè)務數(shù)據(jù)需求(需求!)的數(shù)據(jù)庫,請仔細計劃和測試。您需要考慮如果(何時!)遷移因錯誤而失敗時該怎么辦。

          我放棄EF6中的EF遷移的最初原因是它在啟動時自動遷移運行良好,但它在部署時引發(fā)錯誤!而且很難找到遷移中的錯誤-僅此一項就使我遠離使用EF遷移(要獲得更多信息,可以查看這篇老文章[8])。

          EF Core的遷移處理要比EF6更好:已可以實現(xiàn)自動遷移,并且EF Core遷移對git-merge更加友好,僅提及兩個更改。

          而且,我構建SQL遷移腳本的方式使我比正在運行Add-Migration時要更加仔細地思考自己在做什么。EF Core是一個非常出色的O / RM,有時確實有許多隱藏功能。創(chuàng)建SQL遷移腳本使我從數(shù)據(jù)庫的角度考慮了遷移問題,而且我經(jīng)常會對數(shù)據(jù)庫和C#代碼的一些細微調(diào)整,以使數(shù)據(jù)庫更好的運行。

          References

          [1]?充分的文檔記錄:?https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/

          [2]?Microsoft的有關創(chuàng)建遷移的文檔:?https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/#create-a-migration
          [3]?Microsoft手動修改遷移的示例:?https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/#customize-migration-code
          [4]?GitHub的FluentMigrator:?https://github.com/fluentmigrator/fluentmigrator
          [5]:https://www.thereformedprogrammer.net/wp-content/uploads/2019/01/SQLServerObjectExplorerCompareSchema.png

          [6]?CompareEfSql文檔頁面中找到:?https://github.com/JonPSmith/EfCore.TestSupport/wiki/9.-EfSchemaCompare
          [7]?老文章:?https://www.thereformedprogrammer.net/handling-entity-framework-database-migrations-in-production-part-1-applying-the-updates/


          瀏覽 53
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人区精品一区二区婷婷255 | 中文人妻无码一区二区三区不卡 | 99香蕉视频 | 最新中文字幕MV第三季歌词完整版 | 操逼的网|