在.NET Core類庫中使用EF Core遷移數(shù)據(jù)庫到SQL Server的方法
前言
如果大家剛使用EntityFramework Core作為ORM框架的話,想必都會遇到數(shù)據(jù)庫遷移的一些問題。
起初我是在ASP.NET Core的Web項目中進行的,但后來發(fā)現(xiàn)放在此處并不是很合理,一些關(guān)于數(shù)據(jù)庫的遷移,比如新增表,字段,修改字段類型等等,不應(yīng)該和最上層的Web項目所關(guān)聯(lián),數(shù)據(jù)的遷移文件放到這里也感覺有點多余,有點亂亂的感覺,所以才想著單獨出來由專門的項目進行管理會比較好,也比較清晰!
注意目標框架選擇的是.NET Core 2.0而不是.NET Standard 2.0。
0、前期準備
a)、表實體定義,這個是在.NET Standard 2.0的類庫中存放的。
/// <summary>
/// 系統(tǒng)應(yīng)用的用戶實體
/// </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的類庫,并定義好我們所要使用的數(shù)據(jù)庫上下文,很簡單,接下來開始我們的正文
/// <summary>
/// 系統(tǒng)上下文
/// </summary>
public class LightContext : DbContext
{
public LightContext(DbContextOptions<LightContext> options) : base(options)
{
}
/// <summary>
/// 系統(tǒng)應(yīng)用用戶
/// </summary>
public DbSet<ApplicationUser> ApplicationUser { get; set; }
/// <summary>
/// 角色表
/// </summary>
public DbSet<Role> Role { get; set; }
}
1、問題匯總
首先要確保倉儲類庫中已經(jīng)引入以下兩個Nuget包,沒有的話請使用包管理器進行安裝。不建議直接引入原包:Microsoft.AspNetCore.All,按需引入即可
Install-Package Microsoft.EntityFrameworkCore.SqlServer Install-Package Microsoft.EntityFrameworkCore.Tools
a)打開CMD,然后切換到類庫所在路徑下,執(zhí)行以下命令。不過你也可以使用程序包管理器控制臺(PMC)進行遷移,但是會有少許變化,部分命令見下表:
| 遷移命令描述 | CMD命令 | PMC命令 |
| 創(chuàng)建遷移:migrationname為遷移名稱 | dotnet ef migrations add migrationname | add-migration migrationname |
| 移除遷移(刪除最近的一次遷移) | dotnet ef migrations remove | remove-migration |
| 應(yīng)用最新的遷移(使遷移文件應(yīng)用到數(shù)據(jù)庫) | dotnet ef database update | update-database |
| 應(yīng)用指定的遷移 | dotnet ef database update migrationname | update-database migrationname |
| 查看遷移列表 | dotnet ef migrations list | |
| 查看數(shù)據(jù)庫上下文信息 | dotnet ef dbcontext info |
dotnet ef

錯誤提示:
未找到與命令“dotnet-ef”匹配的可執(zhí)行文件
解決方法:
在項目文件Light.Repository.csproj中添加以下節(jié)點
<ItemGroup> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" /> </ItemGroup>
重新執(zhí)行上面的命令,如果出現(xiàn)了EF Core的標志(一頭蓄勢待發(fā)的野馬)表示已經(jīng)成功

b)、執(zhí)行以下命令進行遷移
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'.
解決方法:
在項目文件中添加以下節(jié)點:
<PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> <RuntimeFrameworkVersion>2.0.3</RuntimeFrameworkVersion> </PropertyGroup>
c)、重新執(zhí)行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的鏈接字符串的話,是不會出現(xiàn)此問題的。很顯然是遷移命令沒有找到DbConnectionString導(dǎo)致的,接下來我們按照提示,實現(xiàn)一個IDesignTimeDbContextFactory<LightContext>試試
解決方法:
創(chuàng)建一個與DbContext同一目錄下的DesignTimeDbContextFactory文件,然后實現(xiàn)接口中的方法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);
}
}
再次執(zhí)行遷移命令,終于成功了。

成功提示:
Done. To undo this action, use 'ef migrations remove'
同時類庫下面會生成Migrations文件夾以及相關(guān)的遷移文件

2、小試遷移命令
a)、使用以下命令應(yīng)用遷移,生成數(shù)據(jù)庫和表
dotnet ef database update

通過VS的SQL Server資源管理器查看生成數(shù)據(jù)庫的結(jié)構(gòu),其中__EFMigrationsHistory為每次遷移的記錄表

b)、因為string類型的字段遷移到數(shù)據(jù)庫之后的數(shù)據(jù)類型為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);
});
}
然后同樣使用上面的兩條命令重新遷移并更新數(shù)據(jù)庫結(jié)構(gòu)

觀察數(shù)據(jù)庫表結(jié)構(gòu)已經(jīng)更新

同理添加字段,刪除字段都是一樣的遷移操作,還是很方便的
3、擴展
a)、為了方便演示,其實上面在類庫中執(zhí)行遷移時的數(shù)據(jù)庫連接字符串是寫死的,那么最好的辦法是應(yīng)該去讀取Web項目下已經(jīng)配置好的連接,這樣就能保證上下的一致性,不用再去為了EF的遷移而單獨維護一個多余的數(shù)據(jù)庫連接配置。改造也很簡單,即通過Configuration組件讀取appsettings.json的ConnectionStrings節(jié)點,改造之后是這樣子的:
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<LightContext>
{
public LightContext CreateDbContext(string[] args)
{
Directory.SetCurrentDirectory("..");//設(shè)置當前路徑為當前解決方案的路徑
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來說還沒有達到可以調(diào)整數(shù)據(jù)庫生成字段的順序,不過我們還是可以修改遷移文件的實體屬性的順序來達到我們想要的效果。下面是我調(diào)整之后重新生成的表,是不是看出來和上面的有什么不同,一圖勝萬語:

c)、最后一步,自己動手試試看:創(chuàng)建一個SeedData遷移文件來添加數(shù)據(jù)庫的初始數(shù)據(jù)。:)
4、最后
EF Core的強大遠不止這些,還有更多的使用方法等著我們?nèi)グl(fā)現(xiàn),去探索。每天進步一點點,是件很愉快的事情!
- .net如何優(yōu)雅的使用EFCore實例詳解
- ASP.NET?Core?5.0中的Host.CreateDefaultBuilder執(zhí)行過程解析
- .Net Core中使用EFCore生成反向工程
- ASP.NET Core使用EF保存數(shù)據(jù)、級聯(lián)刪除和事務(wù)使用
- ASP.NET?Core使用EF查詢數(shù)據(jù)
- ASP.NET?Core使用EF創(chuàng)建模型(索引、備用鍵、繼承、支持字段)
- ASP.NET?Core使用EF?SQLite對數(shù)據(jù)庫增刪改查
- .net core實用技巧——將EF Core生成的SQL語句顯示在控制臺中
- 詳解.Net Core 權(quán)限驗證與授權(quán)(AuthorizeFilter、ActionFilterAttribute)
- .net連接oracle的3種實現(xiàn)方法
- C#利用ODP.net連接Oracle數(shù)據(jù)庫的操作方法
- .Net使用EF Core框架連接Oracle的方法
相關(guān)文章
數(shù)據(jù)庫 數(shù)據(jù)類型float到C#類型decimal, float數(shù)據(jù)類型轉(zhuǎn)化無效
數(shù)據(jù)庫 數(shù)據(jù)類型float到C#類型decimal, float數(shù)據(jù)類型轉(zhuǎn)化無效的解決方法2009-07-07
ASP.NET連接數(shù)據(jù)庫并獲取數(shù)據(jù)方法總結(jié)
這篇文章主要介紹了ASP.NET連接數(shù)據(jù)庫并獲取數(shù)據(jù)方法,結(jié)合實例分析總結(jié)了ASP.NET連接數(shù)據(jù)庫及獲取數(shù)據(jù)的相關(guān)實現(xiàn)技巧,并附帶了web.config配置文件的使用方法與相關(guān)注意事項,需要的朋友可以參考下2015-11-11
已有打開的與此命令相關(guān)聯(lián)的DataReader,必須首先將它關(guān)閉。對于此異常的理解
今天與大家分享一下 已有打開的與此命令相關(guān)聯(lián)的DataReader,必須首先將它關(guān)閉。這個異常的個人理解2012-01-01

