文章内容
2017/5/10 10:38:53,作 者: 黄兵
Entity Framework Code First 方式下,修改 POCO 后,自动重建数据库,并插入初始记录
Code First 已生成数据库,之后,POCO 如被修改,再访问数据库将报以下异常:
The model backing the 'DbName' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the RecreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.
因为 Code First 创建数据库时,除了为 POCO 创建对应表之外,还会创建 1 个名为 EdmMetadata 的表,该表用于记录自动创建数据库时使用的模型对象的形状。因此 Entity Framework 能发现 POCO 与数据库的不同步。
此时,可采用以下方式同步 POCO 与数据库:
- 手动更新数据库。
- 删除数据库,然后重新运行应用程序,让 EF 自动重新创建数据库。
- 开启 EF 代码优先功能,当数据模型发生任何改变时能够自动更新数据库。
在 EF Code First 类库的 CTP 4 版本中包括了一个非常有用的开发时 (development-time) 功能,它允许你在任意时刻修改数据模型类,并自动重建数据库。当你开启这项功能的时候,EF 能够识别用来创建数据库的类模型在何时被改动,何时可以重建你的数据库以匹配新的模型类——你不需要做任何手工操作。
这项功能在开发应用程序的前期特别实用,因为它为快速地重构模型代码带来了很大的自由度和灵活性——无需手动地保持数据库结构的同步。它特别适合 SQL CE,因为 SQL CE 是一个基于文件的数据库而且可以随时在运行时删除和创建。这使得开发流程变得不可思议的流畅。
启用 RecreateDatabaseIfModelChanges 功能最简单的方法就是在 Global.asax 类中的 Application_Start()事件处理函数中加上 Database.SetInitializer()方法的调用。代码如下:
void Application_Start(){Database.SetInitializer<CmsDbContext>(new RecreateDatabaseIfModelChanges<CmsDbContext>());RegisterRoutes(RouteTable.Routes);}
上述代码将 Entity Framework 设置为:当模型被修改时重新创建数据库。
显然这种行为不能用于生产数据库——全部数据将在重建时丢失。
可使用以下方案,在创建或者重建数据库时产生默认或测试数据:
// Step 1 定义派生类public clas CmsInitializer : RecreateDataaseIfModelChanges<CmsDbContext>{protected override void Seed(CmsDbContext context){var roleOfStaffs = new List<RoleOfStaff>{new RoleOfStaff {...},new RoleOfStaff {...},};roleOfStaffs.ForEach(d => context.Dinners.Add(d));}}// Step 2 在 Global.asax 中注册自动调用:void Application_Start(){Database.SetInitializer<CmsDbContext>(new CmsInitializer());RegisterRoutes(RouteTable.Routes);}
上述代码使得任何时候更新模型类之后,数据库都会被删除并重建、同时添加上述硬编码的若干条初始记录。
上述的功能使我们非常容易地在开发时改进和重构代码——不需要用到任何工具和脚本去手动地保持数据库结构和代码的同步。
由于我们的模型类、LINQ 表达式和 "种子" 测试数据都是强类型,所以我们也可以很快速地用 Visual Studio 的重构工具自动在代码文件中应用所有更改。
本文转载自:码农笔记
评论列表