這里之所以推薦使用生成SQL的方式來應用遷移,是因為將遷移生成SQL腳本后,更具靈活性,主要有以下幾點好處:
1 、我們可以根據需要來在遷移生成的SQL腳本基礎上進行刪級訓者增加腳本
2、可以直接將腳本發給資料庫管理員進行升級,
3、可以檢查遷移生成所生成的SQL腳本的正確性,避免破壞性的升級,
一、環境準備
- 安裝efcore cli 命令列工具:打開程式包管理控制臺,輸入:dotnet tool install --global dotnet-ef,如果已安裝請跳過此步驟,
- 新建一個asp.net core mvc 專案和一個類別庫專案,如下圖
二、創建DbContext
首先往類別庫專案添加EFCore 相關的Nuget包以及應用遷移的dbup-sqlserver包, Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Design、dbup-sqlserver,如下圖所示:

然后定義一個物體模型UserInfo和DbContext
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace EFMigrations.Models
{
public class UserInfo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
}
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace EFMigrations.Models
{
public class MyDbContext : DbContext
{
/// <summary>
/// 這里一定要宣告一個接收DbContextOptions引數的建構式,否則無法正常添加遷移,
/// </summary>
/// <param name="options"></param>
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
public DbSet<UserInfo> UserInfos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
}
}
}
三、配置Web專案
1 添加Microsoft.EntityFrameworkCore.Design Nuget包的參考,參考后,記得重新生成下專案,
2 打開appsettings.Development.json,配置資料庫連接字串,如下所示:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ConnectionStr": "Server=.;Database=TestDb;User Id=sa;Password=xxxx"
}
}
3 打開Startup.cs 檔案,將DbContext注冊到服務容器中,
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(builder=> {
builder.UseSqlServer(Configuration["ConnectionStrings:ConnectionStr"]);
});
services.AddControllersWithViews();
}
三、添加遷移
先看下遷移命令的使用說明,打開程式包管理控制臺,輸入以下命令來查看遷移生成命令的使用方式:
dotnet ef migrations add --help

-s 選項:表示生成遷移時要啟動的專案,這里是EFMigrations.Web
-p 選項:指定要存放遷移檔案的專案根目錄,正常就是DbContext類所在的專案,
-o 選項:可以額外指定遷移檔案要存放的目錄,不指定該選項則默認生成到-p 選項所在專案的Migrations檔案夾下
打開程式包管理控制臺,輸入命令:dotnet ef migrations add InitDatabase -s ./EFMigrations.Web -p ./EFMigrations.Models,來生成首個遷移,這里遷移的名稱可以自定義,不一定要叫InitDatabase.成功后如下圖所示:

// <auto-generated />
using EFMigrations.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace EFMigrations.Models.Migrations
{
[DbContext(typeof(MyDbContext))]
partial class MyDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "3.1.18")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("EFMigrations.Models.UserInfo", b =>
{
b.Property<int>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Email")
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserName")
.HasColumnType("nvarchar(max)");
b.HasKey("UserId");
b.ToTable("UserInfos");
});
#pragma warning restore 612, 618
}
}
}
可以看到MyDbContextModelSnapshot.cs 檔案中的內容此時也記錄了InitDatabase 遷移中的更改,即EF每次生成遷移時是將遷移快照檔案(這里是:MyDbContextmodelSnapshot.cs)中的更改和現有模型進行比較來決定新的遷移中要包含哪些更改的,
四、遷移轉換成SQL腳本
先來看下將ef 遷移轉換成資料庫腳本的命令說明,打開程式包管理控制臺,輸入以下命令來查看EF遷移轉SQL腳本命令的用法:
dotnet ef migrations script --help

FROM 引數:表示從哪個遷移開始生成SQL腳本,如果是從第一個遷移開始生成,那么這個引數傳0,否則第一個遷移無法生成SQL腳本,
TO 引數:表示SQL腳本生成截止到哪一個遷移,在這個遷移后面添加的遷移將不會生成SQL腳本,
-s 選項:指定生成SQL腳本時的啟動專案的csproj檔案的路徑,可以是一個相對于當前目錄的相對路徑(程式包管理控制臺打開時默認當前目錄是在.sln檔案所在目錄),啟動專案指的是包含Main函式的可執行的專案,這里就是EFMigrations.Web
-p 選項:指定遷移所在的專案,一般該路徑指定為包含DbContext類的專案的根目錄,和 -s 一樣,也是使用相對于當前目錄的相對路徑來指定,可以使用
dir 命令 來查看當前所在目錄,
-o 選項:用于指定將SQL腳本生成到那個路徑下,可以是一個相對目錄,
輸入 cd ./EFMigrations.Models 進入到包含DbContext類的專案根目錄下,這樣我們就可以不用特意指定DbContext 所在的專案路徑,
輸入 dotnet ef migrations script 0 20210826142318_InitDatabase -s ../EFMigrations.Web -o ./SqlScripts/InitDatabase.sql
上面這個命令表示將20210826142318_InitDatabase 這個遷移生成的SQL存放到EFMigrations.Models/SqlScripts 目錄下,
成功后,可以看到如下圖所示:
注意:洗掉遷移盡量使用dotnet ef migrations remove 來洗掉,盡量不要手動洗掉遷移檔案,因為如果手動洗掉遷移檔案,必須手動將遷移快照(MyDbContextModelSnapShot.cs)檔案里關于這個遷移的變更一起洗掉,否則無法再次生成這個遷移,
需要將.sql 腳本設定為內嵌資源,滑鼠右擊.sql腳本,選擇屬性->生成操作->嵌入的資源,按照如下設定:
五、首個遷移應用
1、在EFMigrations.Models 專案下添加 ApplicationBuilderExtensions類
using DbUp;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace EFMigrations.Models
{
public static class ApplicationBuilderExtensions
{
public static void DbMigrate(this IApplicationBuilder builder, IConfiguration configuration,ILogger logger)
{
string connectionString = configuration["ConnectionStrings:ConnectionStr"];
//如果資料庫還不存在,則創建
EnsureDatabase.For.SqlDatabase(connectionString);
//這里將會去找當前程式集中所包含的所有.sql 腳本,并且找出未被升級的sql腳本進行升級,
var upgrader = DeployChanges.To
.SqlDatabase(connectionString)
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
.LogToConsole()
.Build();
var result = upgrader.PerformUpgrade();
if (!result.Successful)
{
logger.LogInformation(result.Error, "資料庫升級失敗");
}
}
}
}
2、打開EFMigrations.Web 下的Startup.cs檔案,修改Configure方法如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
//這里開始應用資料庫遷移
app.DbMigrate(Configuration,logger);
}
成功后,可看到已經創建了資料庫TestDb 和 表 UserInfo
這里SchemaVersions 是db-sqlserver 創建的用于記錄那些SQL腳本已被應用的表,
六、變更遷移應用
上面僅僅只是創建了一個遷移,假設我們這個時候又往UserInfo物體新增了幾個欄位,那么我們要這個模型的變更同步到正式環境的資料庫改怎么做呢?
1、 生成遷移
dotnet ef migrations add UserInfo_AddColumns -p ./EFMigrations.Models/EFMigrations.Models.csproj -s ./EFMigrations.Web/

2、遷移轉換成SQL腳本,并嵌入到程式集,然后將程式集編譯發布到正式環境
cd ./EFMigrations.Models
dotnet ef migrations script 20210826142318_InitDatabase 20210830142733_UserInfo_AddColumns -o ./SqlScripts/UserInfo_AddColumns.sql -s ../EFMigrations.Web/
這里-o 后面一定要指定sql檔案名,如果只指定目錄如:-o ./SqlScripts/ 則會提示路徑找不到,
另外需要注意的是:FROM 引數指定的遷移(20210826142318_InitDatabase )是會被排除在外的,不會生成相應的SQL腳本,

生成SQL腳本后記得將該腳本的生成操作設定為嵌入資源,
3、重啟網站即可,

可以看到,重啟網站后,欄位創建成功了,
dbup 官方檔案地址:https://dbup.readthedocs.io/en/latest/#getting-started
337901356
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/295812.html
標籤:.NET技术
上一篇:c# 異步呼叫 利用委托異步呼叫
下一篇:通過模板匯出word



