MVC5+EF6 入门完整教程八

简介: 原文:MVC5+EF6 入门完整教程八本篇是相对独立的一篇,主要讲解不丢失数据进行数据库结构升级。 前面我们讲解EF功能时(见第三篇文章)已经介绍过一种更新数据库的方式: EF比较model和database,如果两边不一致,程序将会drop and re-create数据库。
原文: MVC5+EF6 入门完整教程八

本篇是相对独立的一篇,主要讲解不丢失数据进行数据库结构升级。

前面我们讲解EF功能时(见第三篇文章)已经介绍过一种更新数据库的方式:

EF比较model和database,如果两边不一致,程序将会drop and re-create数据库。

本篇文章我们会使用 code first migrations的方式。

这个功能可以使你改变data model,在不drop and re-create数据库的情况下更新数据库的结构,将这些改变部署到生产环境中。

下面就着重介绍如何使用此功能。

文章提纲

  • 前置条件
  • 启用迁移功能
  • 执行迁移
  • 总结

前置条件

先回顾下之前EF修改模型的方式。

我们事先配置好EF,每次数据模型改变的时候都会drop and re-create数据库。

例如你增加、删除、改变实体类,或改变DbContext类后,运行程序时将会自动删除已有的数据库,创建一个新数据库来匹配修改后的模型,同样也会根据Seed方法中内容新建test data.

这种保持database和data model同步的方法在开发阶段很方便。

如果已经部署到生产环境中就不行了, 例如表中扩充一些字段啥的, 原来的数据就不能丢失。

我们禁用原来更新数据库的方式,将web.config中contexts配置节注释掉。

另外我们不用原来数据,改下数据库名,这样可以生成一个新的数据库,方便做实验。

启用迁移

下面就启用Code First Migrations来解决数据库更新的问题。

  1. 打开Package Manager Console

  1. 连续输入如下指令:

    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.

  2. 配置Seed方法

使用drop and re-create的方式时,因为每次model改变时数据库都会被删除,所有数据都会丢失,所以需要使用DALàAccountInitilizer.cs的Seed方法来插入测试数据。

使用Code First Migrations方式,当数据库改变时测试数据会保留,所以包含test data的Seed方法一般来说是不需要的。

如果我们要部署数据库到生产环境,事实上这种情况下我们也不想Seed方法来插入测试数据到生产环境中。

生产环境中用到Seed方法的例子: 比如在我们部署时获得了实际的初始化数据,如实际存在的组织部门这些初始化的信息。

我们为了做实验方便,还是插入一些测试数据。

先插入SysUser和SysRole

类似于前面文章提到的,Seed方法接收一个database context参数,利用这个参数添加新的实体到数据库中。

对每个实体类型:

  1. 新建一个实体集合
  2. 添加到相应的DbSet属性
  3. 保存更改到数据库中

如果大家还记得之前的文章可以发现有一点不同,以前都是用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.

好了,今天就到这里。

欢迎大家多多评论,让下一篇文章更好 :)

目录
相关文章
|
前端开发 数据库 存储
MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
原文:MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用   摘要: 第一阶段1~10篇已经覆盖了MVC开发必要的基本知识。 第二阶段11~20篇将会侧重于专题的讲解,一篇文章解决一个实际问题。
1284 0
|
XML 前端开发 定位技术
MVC 5 + EF6 入门完整教程14 -- 动态生成面包屑导航
原文:MVC 5 + EF6 入门完整教程14 -- 动态生成面包屑导航 上篇文章我们完成了 动态生成多级菜单 这个实用组件。 本篇文章我们要开发另一个实用组件:面包屑导航。 面包屑导航(BreadcrumbNavigation)这个概念来自童话故事"汉赛尔和格莱特",当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现在沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路。
1203 0
|
Web App开发 前端开发 容器
MVC5+EF6 入门完整教程13 -- 动态生成多级菜单
原文:MVC5+EF6 入门完整教程13 -- 动态生成多级菜单 稍微有一定复杂性的系统,多级菜单都是一个必备组件。 本篇专题讲述如何生成动态多级菜单的通用做法。 我们不用任何第三方的组件,完全自己构建灵活通用的多级菜单。
1062 0
|
Web App开发 前端开发
MVC5+EF6 入门完整教程12--灵活控制Action权限
原文:MVC5+EF6 入门完整教程12--灵活控制Action权限 大家久等了。 本篇专题主要讲述MVC中的权限方案。 权限控制是每个系统都必须解决的问题,也是园子里讨论最多的专题之一。 前面的系列文章中我们用到了 SysUser, SysRole, SysUserRole 这几个示例表。
1173 0
|
SQL 安全 测试技术
MVC5+EF6 完整教程17--升级到EFCore2.0
原文:MVC5+EF6 完整教程17--升级到EFCore2.0 EF Core 2.0上周已经发布了,我们也升级到core 文章内容基于vs2017,请大家先安装好vs2017(15.3). 本篇文章主要讲下差异点,跟之前一样的就不再重复了。
1310 0
|
前端开发 .NET 开发框架
MVC 5 + EF6 完整教程16 -- 控制器详解
原文:MVC 5 + EF6 完整教程16 -- 控制器详解 Controller作为持久层和展现层的桥梁, 封装了应用程序的逻辑,是MVC中的核心组件之一。 本篇文章我们就来谈谈 Controller, 主要讨论两个方面: Controller运行机制简介 Controller数据传递方式...
1062 0
|
Web App开发 前端开发 容器
MVC 5 + EF6 完整教程15 -- 使用DI进行解耦
原文:MVC 5 + EF6 完整教程15 -- 使用DI进行解耦 如果大家研究一些开源项目,会发现无处不在的DI(Dependency Injection依赖注入)。 本篇文章将会详细讲述如何在MVC中使用Ninject实现DI 文章提纲 场景描述 & 问题引出 第一轮重构 引入Ninject 第二轮重构 总结 场景描述 & 问题引出 DI是一种实现组件解耦的设计模式。
938 0