最近一不小心偷个懒就已经过了好几个月了,真是惭愧惭愧,出来混终究是要还的,我还是把”脱坑指南“写完吧,-_-~~。点我打开上篇博客
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脚本直接在数据库中执行。