本篇是相對獨立的一篇,主要講解不丟失數據進行數據庫結構升級。html
前面咱們講解EF功能時,已經介紹過一種更新數據庫的方式:web
EF比較model和database,若是兩邊不一致,程序將會drop and re-create數據庫。數據庫
本篇文章咱們會使用 code first migrations的方式。ide
這個功能可使你改變data model,在不drop and re-create數據庫的狀況下更新數據庫的結構,將這些改變部署到生產環境中。測試
下面就着重介紹如何使用此功能。3d
先回顧下以前EF修改模型的方式。code
咱們事先配置好EF,每次數據模型改變的時候都會drop and re-create數據庫。htm
例如你增長、刪除、改變實體類,或改變DbContext類後,運行程序時將會自動刪除已有的數據庫,建立一個新數據庫來匹配修改後的模型,一樣也會根據Seed方法中內容新建test data.blog
這種保持database和data model同步的方法在開發階段很方便。開發
若是已經部署到生產環境中就不行了, 例如表中擴充一些字段啥的, 原來的數據就不能丟失。
咱們禁用原來更新數據庫的方式,將web.config中contexts配置節註釋掉。
另外咱們不用原來數據,改下數據庫名,這樣能夠生成一個新的數據庫,方便作實驗。
下面就啓用Code First Migrations來解決數據庫更新的問題。
enable-migrations 和 add-migration InitialCreate
enable-migrations指令:
a.在項目根目錄下建立了一個Migrations文件夾
b.在Migrations文件夾下新建一個Configuration.cs文件。
能夠經過修改Configuration.cs來對Migration作一些配置(如加入一些測試數據等)
Note
若是前面沒修改web.config的數據庫名, 執行enable-migrations指令後,Migrations將會找到已有的數據庫MVCDemo而後自動執行add-migration指令。
相似咱們第三篇文章中講到 DALàAccountInitilizer.cs類,Configuration類也包含一個Seed方法。
當數據庫新建或數據庫結構更新後,這個方法會被調用,利用這個方法能夠插入或更新test data.
使用drop and re-create的方式時,由於每次model改變時數據庫都會被刪除,全部數據都會丟失,因此須要使用DALàAccountInitilizer.cs的Seed方法來插入測試數據。
使用Code First Migrations方式,當數據庫改變時測試數據會保留,因此包含test data的Seed方法通常來講是不須要的。
若是咱們要部署數據庫到生產環境,事實上這種狀況下咱們也不想Seed方法來插入測試數據到生產環境中。
生產環境中用到Seed方法的例子: 好比在咱們部署時得到了實際的初始化數據,如實際存在的組織部門這些初始化的信息。
咱們爲了作實驗方便,仍是插入一些測試數據。
先插入SysUser和SysRole
相似於前面文章提到的,Seed方法接收一個database context參數,利用這個參數添加新的實體到數據庫中。
對每一個實體類型:
若是你們還記得以前的文章能夠發現有一點不一樣,之前都是用Add方法,此次用了AddOrUpdate方法來插入數據。
sysUsers.ForEach(s => context.SysUsers.AddOrUpdate(p => p.UserName, s));
每次執行update-databse指令時都會執行Seed方法,通常來講,每次遷移後,你不單單是插入數據,例如你想要插入的數據在你建立數據庫的第一次遷移後已經在數據庫中了,這種狀況下更新原有數據就能夠了。
AddOrUpdate正好能夠解決這個問題:
若是數據不存在,插入數據;若是數據存在,更新這筆數據。
context.SysUsers.AddOrUpdate(p => p.UserName, s)
第一個參數p.UserName就是檢查數據是否存在的主鍵。
咱們的測試數據中,假設UserName都不能重複。
做爲比較,咱們添加SysUserRole實體類型的時候沒有使用AddOrUpdate,直接人爲判斷是否存在,不存在再插入。
編譯下項目,下面開始更新數據庫。
前面執行 add-migration時,一樣在Migrations文件夾裏面,產生一個<timestamp>_InitialCreate.cs的文件。
裏面兩個方法,Up和Down:
Up方法建立數據庫表,Down方法刪除表。
public override void Up()
{
CreateTable(
"dbo.SysRole",
c => new
{
ID = c.Int(nullable: false, identity: true),
RoleName = c.String(),
RoleDesc = c.String(),
})
.PrimaryKey(t => t.ID);
CreateTable(
"dbo.SysUserRole",
c => new
{
ID = c.Int(nullable: false, identity: true),
SysUserID = c.Int(nullable: false),
SysRoleID = c.Int(nullable: false),
})
.PrimaryKey(t => t.ID)
.ForeignKey("dbo.SysRole", t => t.SysRoleID, cascadeDelete: true)
.ForeignKey("dbo.SysUser", t => t.SysUserID, cascadeDelete: true)
.Index(t => t.SysUserID)
.Index(t => t.SysRoleID);
CreateTable(
"dbo.SysUser",
c => new
{
ID = c.Int(nullable: false, identity: true),
UserName = c.String(),
Email = c.String(),
Password = c.String(),
})
.PrimaryKey(t => t.ID);
}
public override void Down()
{
DropForeignKey("dbo.SysUserRole", "SysUserID", "dbo.SysUser");
DropForeignKey("dbo.SysUserRole", "SysRoleID", "dbo.SysRole");
DropIndex("dbo.SysUserRole", new[] { "SysRoleID" });
DropIndex("dbo.SysUserRole", new[] { "SysUserID" });
DropTable("dbo.SysUser");
DropTable("dbo.SysUserRole");
DropTable("dbo.SysRole");
}
下面咱們就執行正式遷移。打開Package Manager Console
輸入 update-database
update-database指令調用了Up方法來新建database的表(和data model entity set對應), 而後調用Seed方法來填充測試數據。
這個時候測試下程序,打開數據庫看下,徹底符合咱們的預期。
再進一步,咱們添加一個表Test
先添加一個Model
修改AccountContext.cs, 增長一個data model entity set
執行add-migration AddTestTable和update-database, 完成數據庫表的添加。
去數據庫中檢查,發現已經多了Test這張表了。
最後再檢查下新產生的配置文件。
你們如今應該能充分理解到add-migration時產生的文件的做用了吧。
本次咱們主要講解了數據庫遷移/升級的問題。
主要分爲 啓用遷移(enable-migrations) 和 執行遷移(add-migration, update-database) 兩大步驟。
啓用遷移:產生遷移相關文件夾Migrations和文件夾中相關的配置文件。
執行遷移:產生相關的遷移更改文件並執行更改。
請充分理解本篇文章所講的例子, 後面文章會屢次用到add-migration.