最近一不小心偷個懶就已經過了好幾個月了,真是慚愧慚愧,出來混終究是要還的,我還是把”脫坑指南“寫完吧,-_-~~。點我打開上篇博客
0x001、架構名”dbo”の殤
坑之首也,當提架構名,在mssqlServer中dbo是默認的架構,在codeFirst中默認的架構名就是dbo,舉個栗子先。
新建一個工程(參照上篇文章),創建兩個類型
public class Student { public int Id { get; set; } [MaxLength(100)] public string NickName { get; set; } } public class Class { public int Id { get; set; } public virtual ICollection<Student> Students { get; set; } public int MaxNumber { get; set; } }
在控制台一次執行Enable-Migrations、Add-Migration newModel、update-database -v,如此可得到一個數據庫實例。
現在需求改變了,Class類型中不要Students了,現在把Students屬性注釋掉。
再次執行命令:add-migration removeStudents、 update-database,結果如下所示:
其報錯”Table’codefirstdemodb.dbo.students’doesn’t exist”,codefirstdemodb.dbo是什么鬼東西?
1、codefirstdemodb是我們在配置文件中配置的數據庫實例名稱。
2、dbo是codeFirst默認的架構名稱。
而在mysql數據庫中的默認的架構(Schema)卻是codefirstdemodb。
那么答案就很明顯了,codefirstdemodb.dbo.students當然找不到了。在mysql中的Schema就是數據庫實例的名稱,然而在CodeFirst框架中默認的架構(Schema)名稱是dbo。
此時問題已經找到了,那么如何解決呢?方法有二:
1、修改CodeFirst框架的默認架構。
2、修改遷移文件自動生成的代碼中的架構名。
關於方法1,我已經嘗試了多種途徑,但無一生效,我覺得應該是兼容性問題,如果有大能解決了,還望賜教。
方法2就很簡單了,因為數據庫中表名是不重復的,所以直接是用表名就能找到,把架構名稱刪除就好。
打開遷移自動生成的代碼:
直接替換
如下圖所示:
public override void Up() { DropForeignKey("Students", "Class_Id", "Classes"); DropIndex("Students", new[] { "Class_Id" }); DropColumn("Students", "Class_Id"); } public override void Down() { AddColumn("Students", "Class_Id", c => c.Int()); CreateIndex("Students", "Class_Id"); AddForeignKey("Students", "Class_Id", "Classes", "Id"); }
這樣生成的sql語句就不再有架構名稱了,再次執行update-database -v,就ok了。
0x002、
每次遷移都要和數據庫中_MigrationHistory 中的數據比對,如果不一致就會報錯,這就不符合我們的實用場景來。
我們希望實體類型只要在數據庫中存在並且結構一致就可以正常訪問。
那么如何實現呢?其實很簡單,只要調用EF的一個API就可以設置了。
public static void SetInitializer<TContext>( IDatabaseInitializer<TContext> strategy ) where TContext : DbContext
例如在EF上下文的構造函數中調用該API。
Database.SetInitializer<MyDbContext>(null);
如此就可以滿足我們的需求了,解藕了EF實體類型和數據庫的耦合。
那么這就會引發另一個問題,我們改動EF實體模型之后,以前是可以自動遷移的,現在數據庫已經和EF實體類型不是一一對應的關系了,如果自動遷移的話,有可能出現意料之外的改動。
這時候,我們就可以通過Update-DataBase -script生成sql腳本,然后檢查,最后把准確無誤的sql腳本直接在數據庫中執行。