從類別程式庫建立 EF Core Migration
1 |
EF Core Migration 可依據 Entity 類別針對不同資料庫(MSSQL、SQLite、Oracle、MySQL...)產生對映的 CREATE TABLE Script,能自動連上資料庫伺服器建好資料表,Entity 修改時還能生出增減修改欄位 ALTER Script (但有一些限制) 套用資料庫直接改版... 是我心中 EF Core 最迷人的特點之一。(另一項很殺的特色 - 改兩行程式,資料庫便能從 Oracle 換成 MSSQL)
不過,之前範例都是單一專案,Entity 類別寫在 ASP.NET Core 專案裡,用哪一種資料庫、連線字串是啥寫在 ASP.NET Core 的 Startup.cs,要建立 EF Core Migration 就在 ASP.NET Core 專案下指令,沒什麼大問題。
實際開發較有規模的專案時,資料庫相關程式常會被分離成類別程式庫 (Class Library),這種情境下建立 EF Core Migration 有一些額外步驟。
在 DbContext 所在的類別程式庫新增一個型別實作 IDesignTimeDbContextFactory<YourDbContextType>,宣告一個 CreateDbContext() 方法建立 YourDbContextType 物件並傳回,在其中決定使用哪一種資料庫、連線字串為何,EF Core 才知道怎麼產生 SQL Script 及更新資料庫。
這個 IDesignTimeDbContextFactory 介面物件會在執行 dotnet ef migrations ... 時被呼叫,若不想將連線字串寫死在程式裡,放進 appSettings.json 裡是個好選擇(還可與網站或應用程式共用讀取及解密連線字串邏輯)。類別程式庫專案要讀 appsettings.json 需引用 Microsoft.Extensions.Configuration.Json NuGet Package,並透過 ConfigurationBuilder() 載入,以下是個範例:()public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ServiceDbContext> { public ServiceDbContext CreateDbContext(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) //會在類別程式庫專案執行,由同目錄取JSON .AddJsonFile("appSettings.json") .Build(); var cnStr = config.GetConnectionString("MYDB"); //TODO: 正式應用時且連線字串含密碼時應加密儲存 if (string.IsNullOrEmpty(cnStr)) throw new ApplicationException("Missing .config connection string [MYDB]"); var ctxBuilder = new DbContextOptionsBuilder(); ctxBuilder.UseSqlite(cnStr); return new ServiceDbContext(ctxBuilder.Options); } }
在類別程式庫放入 appsettings.json:
{ "ConnectionStrings": { "MYDB": "data source=MyDB.db" } }
直接在類別程式庫專案執行 dotnet ef migrations add InitCreate 會冒出以下錯誤:
Startup project 'MyClassLib.csproj' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core .NET Command-line Tools with this project, add an executable project targeting .NET Core or .NET Framework that references this project, and set it as the startup project using --startup-project; or, update this project to cross-target .NET Core or .NET Framework. For more information on using the EF Core Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034781
理由是 EF 工具必須靠 EXE 或 ASP.NET 網頁執行建立 Process 載入類別程式庫運作,因此要加上 --startup-project 指向主控台或網站專案所在資料夾,例如:
dotnet ef migrations add InitCreate --startup-project ..\web_or_console_app_project_folder
提醒:--startup-project 所指的專案需參照 Microsoft.EntityFramework.Core.Design NuGet Package.
這樣,就能用專屬的 appsettings.json 決定連線 DB,在類別程式庫中建立 EF Core Migration 類別跟 SQL Script 了。
【延伸閱讀】
- EF Core Migrations with DbContext in Separate Library by Manoj Choudhari
- EF Core 筆記 1 - 概論
- ASP.NET Core CRUD 傻瓜範例 (2) - 資料庫準備
- EF Core 筆記 4 - 跨資料庫能力展示
- ASP.NET Core 練習 - EF Core 單元測試
Tips of how to use EF Core Migragtions in class library.
Comments
# by rich
var ctxBuilder = new DbContextOptionsBuilder(); 少了型別的對應 var ctxBuilder = new DbContextOptionsBuilder<ServiceDbContext>();