在本节中,我们将使用Entity Framework Code First 数据迁移功能将模型类的改变应用到数据库中。

默 认情况下,当我们使用Entity Framework Code First 自动创建一个数据库,像我们之前教程中讲的那样,Code First 添加一个table帮我们跟踪数据库结构是否与模型类同步。如果不同步,Entity Framework 将抛出一个错误,这样更方便我们在开发的时候发现问题,否则只能在运行时通过晦涩的错误来查找了。

为模型更改设置 Code First 数据迁移

在解决方案资源管理器中,删除自动创建的 Movies.mdf 文件。

在工具菜单中,选择“库程序包管理器”>“程序包管理器控制台”:

图1:打开“程序包管理器控制台”菜单项

在“程序包管理器控制台”窗口中输入:Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

图2:运行命令

Enable-Migrations 命令创建了一个Migrations文件夹和Configuration.cs文件。

图3:新添加的文件

打开 Configuration.cs 文件,使用以下代码替换 Seed 方法:

代码清单1:Seed 方法 - Configruation.cs

protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
context.Movies.AddOrUpdate(i => i.Title,
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Price = 7.99M
}, new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 8.99M
}, new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price = 9.99M
}, new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 3.99M
}
);
}

使用这段代码的时候,需要添加 using MvcMovie.Models 的引用。

Code First 数据迁移在每次迁移(在程序包管理器控制台中调用 update-database)的时候都会调用Seed方法。

在进行下一步之前,先编译解决方案,否则下一步会出错误。

下一步,为初始化迁移创建一个 DbMigration 类。这次迁移创建一个新数据库,这也是我们为什么要删除之前的数据库的原因。

在“程序包管理器控制台”窗口,输入命令 add-migration Initial  创建初始化迁移。名称“Initial”是随意命名的,它用来命名创建好的迁移文件。

图4:创建初始化迁移

Code First Migrations 创建在Migrations文件夹中创建了一个文件(文件名是 {DateStamp}_Initial.cs ),这个类包含了创建数据库结构的代码。迁移文件的文件名以DateStamp开头是为了更好的排序,打开 {DateStamp}_Initial.cs  文件,它包含了为数据库MovieDB创建Movies表的指令。当你使用下面的命令更新数据库时,{DateStamp}_Initial.cs  文件将会运行并创建数据库结构,然后将执行 Seed 方法将测试数据插入数据库中。

在“程序包管理器控制台”中输入命令 update-database

图5:执行更新数据库命令

运行应用程序,浏览/Movies 地址,我们在Seed方法中添加的数据如下:

图6:浏览程序

为Movie模型添加Rating字段

上面的内容一直在介绍如何进行数据迁移,现在开始为Movie类添加Rating字段,打开Movie.cs 文件,为它添加一个Rating字段,添加后的代码如下:

代码清单2:添加Rating字段后的Movie类

public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
set; }
}

编译解决方案。

现在我们已经更新了Movie类,你还需要修改\Views\Movies\Index.cshtml  和 \Views\Movies\Create.cshtml 视图。修改后的代码如下:

代码清单3:修改后的Index.cshtml

@model IEnumerable<MvcMovie.Models.Movie>

@{
ViewBag.Title = "Index";
} <h2>Index</h2> <p>
@Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm("Index", "Movies", FormMethod.Get))
{
<p>
Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" />
</p>
} <table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
th>
@Html.DisplayNameFor(model => model.Rating)
</th>
<th></th>
</tr> @foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
td>
@Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
} </table>

代码清单3:修改后的Create.cshtml

@model MvcMovie.Models.Movie

@{
ViewBag.Title = "Create";
} <h2>Create</h2> @using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true) <fieldset class="form-horizontal">
<legend>Movie</legend> <div class="control-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title, null, new { @class = "help-inline" })
</div>
</div> <div class="control-group">
@Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.ReleaseDate)
@Html.ValidationMessageFor(model => model.ReleaseDate, null, new { @class = "help-inline" })
</div>
</div> <div class="control-group">
@Html.LabelFor(model => model.Genre, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Genre)
@Html.ValidationMessageFor(model => model.Genre, null, new { @class = "help-inline" })
</div>
</div> <div class="control-group">
@Html.LabelFor(model => model.Price, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price, null, new { @class = "help-inline" })
</div>
</div> div class="control-group">
@Html.LabelFor(model => model.Rating, new { @class = "control-label" div class="controls">
@Html.EditorFor(model => model.Rating)
@Html.ValidationMessageFor(model => model.Rating, null, new { @class = "help-inline" div>
</div> <div class="form-actions no-color">
<input type="submit" value="Create" class="btn" />
</div>
</fieldset>
} <div>
@Html.ActionLink("Back to List", "Index")
</div> @section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

现在我们已经在程序中为Rating字段做成了修改。再次运行程序,浏览/movies 地址,这时我们会得到一个错误:

图7:错误页面

出现这个错误的原因是Movie模型类发生了变化,而与它对应的数据表 Movie 中并不存在Rating字段。

There are a few approaches to resolving the error:

解决这个问题有以下几种途径:

  1. 让Entity Framework自动删除并根据新的模型自动创建数据库。这种方式在早起开发过程中的测试数据库中非常方便,它可以快速的修改模型和数据库结构。另一方面,这样做将会使你丢失已有的数据,因此这种方式不能用在生产环境的数据库中。
  2. 在数据库中加上Rating字段,使数据库和Model类的结构相同。这种方式的优点是能够保留数据,你可以手动修改或使用数据库脚本修改。
  3. 使用Code First 迁移来升级数据库结构。

在本教程中,我们使用Code First 迁移。

更新Seed 方法,使它为Rating字段提供一个值。打开 Migrations\Configuration.cs 文件,为每一个Movie对象的Rating字段赋值。

代码清单4:修改后的Seek方法

protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
context.Movies.AddOrUpdate(i => i.Title,
new Movie
{
Title = "龙门飞甲",
ReleaseDate = DateTime.Parse("2012-1-11"),
Genre = "动作",
Price = 30M,
Rating = "优"
},
new Movie
{
Title = "冰河世纪",
ReleaseDate = DateTime.Parse("2011-3-1"),
Genre = "动漫",
Price = 65M,
Rating = "良"
},
new Movie
{
Title = "中国合伙人",
ReleaseDate = DateTime.Parse("2013-6-18"),
Genre = "励志",
Price = 70M,
Rating = "良"
}
);
}

重新编译解决方案,然后打开“程序包管理器控制台”,执行命令:add-migration Rating

add-migration 命令告诉迁移程序去检查当前的Movie模型与当前数据库之间的差异,创建迁移数据库到最新模型的代码。名称 Rating 是可以随便命名的,此处用来命名迁移文件。

当命令执行完成之后,Visual Studio 会打开刚刚添加的继承自 DbMigration 的类文件,文件中有两个方法 Up和Down,分别用来升级和降级数据库。在Up方法中我们可以看到为数据库添加列的代码,而Down方法中的代码则是删除Rating列。

代码清单5:Rating类

public partial class Rating : DbMigration
{
public override void Up()
{
AddColumn("dbo.Movies", "Rating", c => c.String());
} public override void Down()
{
DropColumn("dbo.Movies", "Rating");
}
}

编译解决方案,然后执行命令 update-database 。“程序包管理器控制台”窗口的输出如下图(Rating前的时间戳可能不尽相同):

图8:更新数据库

刷新我们出错的页面,你能看到已经加入了Rating字段:

图9:加入了Rating字段的界面

点击“Create New”链接试着添加一个电影信息,不要忘记为Rating字段赋值。

图10:新增页面

输入完成之后点击“Create”按钮,保存电影信息。

图11:保存后的列表

你还需要在Edit、Details和Delete视图中添加Rating字段。

如果你再次执行 "update-database" 命令,将不会做出任何修改,因为数据库结构和模型的结构已经相同了。

现在,通过项目中使用数据迁移,我们在添加字段或更新模型结构的时候不用再删除数据库了。在下一节中,我们将对结构做出更多的更改,并使用数据迁移来更新数据库。

启用自动迁移

一、在 Package Manager Console 下运行命令 Enable-Migrations,完成之后你就会看到如下:

生成了两个类:

这两个类干什么的呢?暂时先不解释 后面的话会在讲解的。这里我分享一个关于迁移的博文有兴趣可以看一下

没兴趣的继续往下看!!

二、EF6 本身已经集成了Migrations 那我们主要演示的是手动去完成迁移的工作,实现在应用程序启动时自动升级

1) 我没有采用上面的方式,我是直接新建了一个Configuration类

2)我们直接来看代码

public class Configuration : DbMigrationsConfiguration<BlogDbContext>
{
/// <summary>
/// 初始化一个<see cref="MigrationsConfiguration"/>类型的新实例
/// </summary>
public Configuration()
{
//启用自动迁移
AutomaticMigrationsEnabled = true;
//获取或设置一个值表示如果在自动数据丢失是可以接受的 [慎重设置]
AutomaticMigrationDataLossAllowed = true;
}
}

核心代码就两句,简单吧! 是不是觉得学习EF so easy! 不能用so easy因为我们这里说的都是最简单的。要想学深入还是由难度的。

三、然后在Global.asax里面添加一下代码,代表应用程序初始化的时候把数据库更新为最新的办法

四、运行效果

mvc數據遷移的更多相关文章

  1. MVC+Ninject+三层架构+代码生成 -- 总结(四、數據層)

    1.數據層使用了SqlSugar 庫類 . 數據層使用了SqlSugar 庫類 ,有興趣的 可以學習  http://www.codeisbug.com/Doc/8/1133,個人覺得比EF 簡單,容 ...

  2. MVC+Ninject+三层架构+代码生成 -- 总结(一、數據庫)

    一.數據表 是參照 別人的庫建表的 ,主鍵都是用int 自增,若是跨數據庫的話,建議使用GUID為主鍵.

  3. Active Record: 資料庫遷移(Migration) (转)

    Active Record: 資料庫遷移(Migration) Programming today is a race between software engineers striving to b ...

  4. Grafana展示報表數據的配置(二)

    一.Grafana以圖表的形式展示KPI報表的結果數據1.按照日期顯示數據達標量與未達標量2.顯示當前報表的最大值.最小值.平均值.總量3.報表結果數據的鏈接分享與頁面嵌入,用戶無需登錄直接訪問報表統 ...

  5. NBU bplabel命令擦除磁帶數據

    bplabel Linux系統,該命令位於NBU server的如下目錄:/usr/openv/netbackup/bin/admincmd bplabel – write NetBackup lab ...

  6. EMC DATA DOMAIN 2200 filesys destroy(數據清空及重建)

    EMC 數據清空 1.數據清空 這裡會清空file system的所有東西包括tapes

  7. Python 基礎 - bytes數據類型

    三元運算 什麼是三元運算?請看下圖說明 透過上圖說明後,可以得出一個三元運算公式: result = 值1 if 條件 else 值2, 如果鯈件為真: result = 值1 如果鯈件為假: res ...

  8. Python 基礎 - 數據類型

    標準數據類型 Python3 中有六個標準的數據類型 1 Number(數字) 2 String(字符串) 3 List (列表) 4 Tuple (元組) 5 Sets (集合) 6 Diction ...

  9. GO語言基礎教程:數據類型,變量,常量

    GO類似PHP,每行的結尾要加分號來結束,不同點在於GO對此並不強制,這一點又像javascript,另外GO的語句塊是用一對大括號來包裹的,但是go要求左大括號必須要在語句的結尾處,不能在行首出現左 ...

随机推荐

  1. 计算细胞数【BFS】

    问题描述 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数. 输入格式 2行:第1行为两个整数 mm, nn, 代表矩阵 ...

  2. Java基础教程(3)--回顾HelloWorld

      在上一篇文章中,我们已经编写了第一个Java程序--HelloWorld,并且对它进行了编译和运行.虽然这个例子很短小,但是它具有一个完整的Java程序所应该具有的结构.在这篇文章中,我将会对这个 ...

  3. oauth2.0授权协议

    参考文章 一.OAuth是什么? OAuth的英文全称是Open Authorization,它是一种开放授权协议.OAuth目前共有2个版本,2007年12月的1.0版(之后有一个修正版1.0a)和 ...

  4. Q:接口与抽象类

    博文回答一下两个问题: 接口和抽象类的区别 选用接口和抽象类的依据 对于问题1: 从java语法的角度上来说,接口的所有成员和方法都是public的,且其方法均为abstract的.直到jdk1.8之 ...

  5. Linux 安装命令

  6. IPtables中SNAT和MASQUERADE的区别

    问题 iptables中snat和MASQUERADE的区别 解决方案 iptables中可以灵活的做各种网络地址转换(NAT) 网络地址转换主要有两种:snat和DNAT snat是source n ...

  7. Android开发如何定制framework层服务

    刚刚跨完年,新年第一篇文章,那么今天将对Android开发framework中间层的服务定制使用作个总结.首先我们先导入Android平台源码framework层的代码到开发工具eclipse中,代码 ...

  8. js重名的处理

    ### 关于重名的处理 > 在变量提升阶段,如果名字重复了,不会重新的进行声明,但是会重新的进行定义(后面赋的值会把前面赋的值给替换掉) ```javascript //=>变量提升:fn ...

  9. macvtap与vhost-net技术

    MacVlan的功能是给同一个物理网卡配置多个MAC地址,可以在软件上配置多个以太网口,属于物理层的功能.MacVTap是用来替代TUN/TAP和Bridge内核模块的.MacTap是基于MacVla ...

  10. select 1 from table 语句中的1代表什么意思

    在这里我主要讨论的有以下几个select 语句: doo_archive表是一个数据表,表的行数为4行,如下: 分别用三条select语句select  1 from doo_archive.sele ...