前言 如果大家剛使用EntityFramework Core作為ORM框架的話,想必都會遇到資料庫遷移的一些問題。 起初我是在ASP.NET Core的Web項目中進行的,但後來發現放在此處並不是很合理,一些關於資料庫的遷移,比如新增表,欄位,修改欄位類型等等,不應該和最上層的Web項目所關聯,數據 ...
前言
如果大家剛使用EntityFramework Core作為ORM框架的話,想必都會遇到資料庫遷移的一些問題。
起初我是在ASP.NET Core的Web項目中進行的,但後來發現放在此處並不是很合理,一些關於資料庫的遷移,比如新增表,欄位,修改欄位類型等等,不應該和最上層的Web項目所關聯,數據的遷移文件放到這裡也感覺有點多餘,有點亂亂的感覺,所以才想著單獨出來由專門的項目進行管理會比較好,也比較清晰!
註意目標框架選擇的是.NET Core 2.0而不是.NET Standard 2.0。
0、前期準備
a)、表實體定義,這個是在.NET Standard 2.0的類庫中存放的。
/// <summary> /// 系統應用的用戶實體 /// </summary> public class ApplicationUser : BaseModel { /// <summary> /// 用戶名 /// </summary> public string UserName { get; set; } /// <summary> /// 密碼 /// </summary> public string Password { get; set; } /// <summary> /// 郵件地址 /// </summary> public string Email { get; set; } }
b)、新建一個.NET Core 2.0的類庫,並定義好我們所要使用的資料庫上下文,很簡單,接下來開始我們的正文
/// <summary> /// 系統上下文 /// </summary> public class LightContext : DbContext { public LightContext(DbContextOptions<LightContext> options) : base(options) { } /// <summary> /// 系統應用用戶 /// </summary> public DbSet<ApplicationUser> ApplicationUser { get; set; } /// <summary> /// 角色表 /// </summary> public DbSet<Role> Role { get; set; } }
1、問題彙總
首先要確保倉儲類庫中已經引入以下兩個Nuget包,沒有的話請使用包管理器進行安裝。不建議直接引入原包:Microsoft.AspNetCore.All,按需引入即可
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
a)打開CMD,然後切換到類庫所在路徑下,執行以下命令。不過你也可以使用程式包管理器控制台(PMC)進行遷移,但是會有少許變化,部分命令見下表:
遷移命令描述 | CMD命令 | PMC命令 |
創建遷移:migrationname為遷移名稱 | dotnet ef migrations add migrationname | add-migration migrationname |
移除遷移(刪除最近的一次遷移) | dotnet ef migrations remove | remove-migration |
應用最新的遷移(使遷移文件應用到資料庫) | dotnet ef database update | update-database |
應用指定的遷移 | dotnet ef database update migrationname | update-database migrationname |
查看遷移列表 | dotnet ef migrations list | |
查看資料庫上下文信息 | dotnet ef dbcontext info |
dotnet ef
錯誤提示:
未找到與命令“dotnet-ef”匹配的可執行文件
解決方法:
在項目文件Light.Repository.csproj中添加以下節點
<ItemGroup> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" /> </ItemGroup>
重新執行上面的命令,如果出現了EF Core的標誌(一頭蓄勢待發的野馬)表示已經成功
b)、執行以下命令進行遷移
dotnet ef migrations add InitLightDB
錯誤提示:
The specified framework version '2.0' could not be parsed
The specified framework 'Microsoft.NETCore.App', version '2.0' was not found.
- Check application dependencies and target a framework version installed at:
\
- Alternatively, install the framework version '2.0'.
解決方法:
在項目文件中添加以下節點:
<PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> <RuntimeFrameworkVersion>2.0.3</RuntimeFrameworkVersion> </PropertyGroup>
c)、重新執行b步驟的命令,報錯信息如下:
錯誤提示:
Unable to create an object of type 'LightContext'. Add an implementation of 'IDesignTimeDbContextFactory<LightContext>' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.
這個問題如果是在Web項目,並且配置了DbContext的鏈接字元串的話,是不會出現此問題的。很顯然是遷移命令沒有找到DbConnectionString導致的,接下來我們按照提示,實現一個IDesignTimeDbContextFactory<LightContext>試試
解決方法:
創建一個與DbContext同一目錄下的DesignTimeDbContextFactory文件,然後實現介面中的方法CreateDbContext,並配置ConnectionString
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<LightContext> { public LightContext CreateDbContext(string[] args) { var builder = new DbContextOptionsBuilder<LightContext>(); builder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Integrated Security=true;Initial Catalog=Light;"); return new LightContext(builder.Options); } }
再次執行遷移命令,終於成功了。
成功提示:
Done. To undo this action, use 'ef migrations remove'
同時類庫下麵會生成Migrations文件夾以及相關的遷移文件
2、小試遷移命令
a)、使用以下命令應用遷移,生成資料庫和表
dotnet ef database update
通過VS的SQL Server資源管理器查看生成資料庫的結構,其中__EFMigrationsHistory為每次遷移的記錄表
b)、因為string類型的欄位遷移到資料庫之後的數據類型為nvarchar(max)並且是可空類型的,下麵我們就使用Fluent API對ApplicationUser表欄位進行配置,同樣你也可以使用屬性註解的方式進行配置,因為我自己不喜歡“污染”表實體
public static void ConfigApplicationUser(ModelBuilder modelBuilder) { modelBuilder.Entity<ApplicationUser>(m => { m.Property(t => t.Email) .HasMaxLength(50); m.Property(t => t.UserName) .IsRequired() .HasMaxLength(50); m.Property(t => t.Password) .IsRequired() .HasMaxLength(20); }); }
然後同樣使用上面的兩條命令重新遷移並更新資料庫結構
觀察資料庫表結構已經更新
同理添加欄位,刪除欄位都是一樣的遷移操作,還是很方便的
3、擴展
a)、為了方便演示,其實上面在類庫中執行遷移時的資料庫連接字元串是寫死的,那麼最好的辦法是應該去讀取Web項目下已經配置好的連接,這樣就能保證上下的一致性,不用再去為了EF的遷移而單獨維護一個多餘的資料庫連接配置。改造也很簡單,即通過Configuration組件讀取appsettings.json的ConnectionStrings節點,改造之後是這樣子的:
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<LightContext> { public LightContext CreateDbContext(string[] args) { Directory.SetCurrentDirectory("..");//設置當前路徑為當前解決方案的路徑 string appSettingBasePath = Directory.GetCurrentDirectory() + "/Light.AuthorityApi";//改成你的appsettings.json所在的項目名稱 var configBuilder = new ConfigurationBuilder() .SetBasePath(appSettingBasePath) .AddJsonFile("appsettings.json") .Build(); var builder = new DbContextOptionsBuilder<LightContext>(); //builder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Integrated Security=true;Initial Catalog=Light;"); builder.UseSqlServer(configBuilder.GetConnectionString("LightConnection")); return new LightContext(builder.Options); } }
註意需要額外引入下麵這個Nuget包:
Install-Package Microsoft.Extensions.Configuration.Json
b)、屬性註解[Column(Order = 1)]對EF Core來說還沒有達到可以調整資料庫生成欄位的順序,不過我們還是可以修改遷移文件的實體屬性的順序來達到我們想要的效果。下麵是我調整之後重新生成的表,是不是看出來和上面的有什麼不同,一圖勝萬語:
c)、最後一步,自己動手試試看:創建一個SeedData遷移文件來添加資料庫的初始數據。:)
4、最後
EF Core的強大遠不止這些,還有更多的使用方法等著我們去發現,去探索。每天進步一點點,是件很愉快的事情!