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来解决数据库更新的问题。
- 打开Package Manager Console

- 连续输入如下指令:
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.

- 配置Seed方法
使用drop and re-create的方式时,因为每次model改变时数据库都会被删除,所有数据都会丢失,所以需要使用DALàAccountInitilizer.cs的Seed方法来插入测试数据。
使用Code First Migrations方式,当数据库改变时测试数据会保留,所以包含test data的Seed方法一般来说是不需要的。
如果我们要部署数据库到生产环境,事实上这种情况下我们也不想Seed方法来插入测试数据到生产环境中。
生产环境中用到Seed方法的例子: 比如在我们部署时获得了实际的初始化数据,如实际存在的组织部门这些初始化的信息。
我们为了做实验方便,还是插入一些测试数据。
先插入SysUser和SysRole

类似于前面文章提到的,Seed方法接收一个database context参数,利用这个参数添加新的实体到数据库中。
对每个实体类型:
- 新建一个实体集合
- 添加到相应的DbSet属性
- 保存更改到数据库中
如果大家还记得之前的文章可以发现有一点不同,以前都是用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 入门完整教程八的更多相关文章
- MVC5+EF6 入门完整教程八:数据迁移
https://www.cnblogs.com/miro/p/4164076.html
- MVC5+EF6 入门完整教程九
前一阵子临时有事,这篇文章发布间隔比较长,我们先回顾下之前的内容,每篇文章用一句话总结重点. 文章一 MVC核心概念简介,一个基本MVC项目结构 文章二 通过开发一个最基本的登录界面,介绍了如何从Co ...
- MVC5+EF6 入门完整教程
MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@20150521 MVC5+EF6 入门完整教程9:多表 ...
- MVC5+EF6 入门完整教程13 -- 动态生成多级菜单
稍微有一定复杂性的系统,多级菜单都是一个必备组件. 本篇专题讲述如何生成动态多级菜单的通用做法. 我们不用任何第三方的组件,完全自己构建灵活通用的多级菜单. 需要达成的效果:容易复用,可以根据mode ...
- MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
摘要: 第一阶段1~10篇已经覆盖了MVC开发必要的基本知识. 第二阶段11-20篇将会侧重于专题的讲解,一篇文章解决一个实际问题. 根据园友的反馈, 本篇文章将会先对呼声最高的仓储模式进行讲解. 文 ...
- MVC5 + EF6 入门完整教程二
从前端的UI开始 MVC分离的比较好,开发顺序没有特别要求,先开发哪一部分都可以,这次我们主要讲解前端UI的部分. ASP.NET MVC抛弃了WebForm的一些特有的习惯,例如服务器端控件,Vie ...
- MVC5+EF6 入门完整教程12--灵活控制Action权限
大家久等了. 本篇专题主要讲述MVC中的权限方案. 权限控制是每个系统都必须解决的问题,也是园子里讨论最多的专题之一. 前面的系列文章中我们用到了 SysUser, SysRole, SysUserR ...
- MVC5+EF6 入门完整教程 总目录
本系列文章会从一个主干开始,逐渐深入,初步规划30篇.初级10篇,中级10篇,综合项目实战10篇 初级10篇 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@201505 ...
- MVC5 + EF6 入门完整教程1
https://www.cnblogs.com/miro/p/4030622.html 第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定& ...
随机推荐
- Lucky and Good Months by Gregorian Calendar - POJ3393模拟
Lucky and Good Months by Gregorian Calendar Time Limit: 1000MS Memory Limit: 65536K Description Have ...
- Cenots7编译Opencv3.1错误:下载ippicv,解决方案
在centos7上安装Opencv的时候,停在了下载ippicv的地方,一直都下载不下来. ippicv是一个并行计算库,其实可以不用的. 如果不想用这个并行计算库,在做Cmake的时候用参数关闭即可 ...
- Java的日期工具类
package com.tech.jin.util; import java.text.DateFormat; import java.text.ParseException; import java ...
- centos6.x开机卡死
问题描述: centos6.x开机卡死在进度条处 远程登录,查看系统日志,看看卡在哪儿 通过远程连接,tail -fn 20 /var/log/messages 发现报错: init: prefdm ...
- java 垃圾回收
转自:http://www.360doc.com/content/13/0305/10/15643_269388816.shtml
- 参考:鼠标点击事件(Selenium)
1.鼠标右键点击操作:Actions action = new Actions(driver) ;action.contextClick(driver.findElement(By.xpath(xpa ...
- CSS篇
一.盒子模型: 标准模式和混杂模式(IE).在标准模式下浏览器按照规范呈现页面:在混杂模式下,页面以一种比较宽松的向后兼容的方式显示.混杂模式通常模拟老式浏览器的行为以防止老站点无法工作. CSS盒子 ...
- Linux文件搜索命令
文件搜索命令:locate locate 文件名 在后台数据库中按文件名搜索,搜索速度很快(比find命令要快得多) locate命令所搜索的后台数据库的位置:/var/bin/mlocate 支持模 ...
- 合并文件夹里多个excel
Sub 合并当前目录下所有工作簿的全部工作表() Dim MyPath, MyName, AWbName Dim Wb As workbook, WbN As String Dim G As Long ...
- LBWE更新模式切换问题:缓存清理
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...