维护模型与数据库结构之间的差别

现在我们已经将应用程序修改完毕,在Movie数据模型中添加了一个Rating属性。现在让我们重新运行应用程序,打开“http://localhost:xx/Movies”这个URL地址,这时,浏览器会显示一个应用程序出错画面。如图所示。

导致这个问题发生的原因是因为在应用程序中,更新后的Movie数据模型类与我们实际连接的数据库结构并不统一(Movies数据表中并没有Rating列)。在默认情况下,当你使用EF code-first自动创建数据库时,EF code-first会自动在数据库中追加数据表来使得数据库的结构与它自动生成的模型类保持同步。如果不同步,EF将会抛出一个错误。这使得在开发程序时对于错误的跟踪会变得更加容易,否则你只能在运行时发现这个错误。同步检查特性正是引起以上显示的错误的原因。

有两种方法可以解决这个错误:

1. 让Entity Framework自动删除当前数据库,并在新的模型类的基础上重新创建该数据库。这种方法在使用一个测试数据库时对于开发来说是十分方便的,因为它允许你快速地同步修改模型与数据库。但缺点是你将丢失现存库中的数据(所以请不要将这个方法使用在实际使用中的数据库上)。

2. 修改数据库中的数据表的结构来使之与数据模型相匹配。这个方法的好处是可以让你保留表中的数据。你可以手工实现这一操作。

现在我们使用第一种方法,在任何模型发生了改变的情况下让EF自动重建数据库。

当模型改变时自动重建数据库

现在我们来修改我们的应用程序,使得我们的应用程序中如果任何模型发生了改变,都将自动删除与重建当前模型所使用的数据库。在解决方案资源管理器中,鼠标右击Modes文件夹,选择“添加”,然后点击“类”,如图所示:

在“添加新项”对话框中,将类名定义为“MovieIntializer”,然后点击添加按钮添加该类。书写该类的代码如下所示:

using System;
using System.Collections.Generic;
using System.Data.Entity.Database;
namespace MvcMovie.Models
{
public class MovieIntializer :
DropCreateDatabaseIfModelChanges<MovieDBContext>
{
protected override void Seed(MovieDBContext context)
{
var movies = new List<Movie> { new Movie { Title = "非诚勿扰 2",
ReleaseDate=DateTime.Parse("2011-1-11"),
Genre="爱情",
Rating="R",
Price=7.00M}, new Movie { Title = "赵氏孤儿",
ReleaseDate=DateTime.Parse("2011-2-23"),
Genre="历史",
Rating="R",
Price=9.00M},
}; movies.ForEach(d => context.Movies.Add(d));
} }
}

使用这个MovieInitializer类之后,一旦我们的数据模型类发生改变后,我们的模型类所映射的数据库都会被自动重建。代码中使用了Seed方法来指定任何时候重建数据库的时候,想要追加到某数据表中的数据。这为将一些示例数据添加到数据表中的操作提供了一个有用的方法,而不需要重建了数据库之后再手工到数据表中添加示例数据。现在我们已经定义好了我们的MovieInitializer类,接下来我们想在整个工程中使用这个类,这样每次在运行我们的应用程序的时候会自动检查当前我们的模型类结构是否与数据库结构不一致,如果不一致的时候就自动重建该数据库,并且追加MovieInitializer类中所指定的默认数据。打开我们的MvcMovies工程的根目录下的Global.asax文件,如图所示:

Global.asax文件中定义了当前工程所使用到的Application(应用程序)主类,包含了一个Application_Start()事件处理器,当第一次运行我们的应用程序时会触发这个事件。让我们在文件头部追加两个有用的声明。第一个声明引用Entity Framework命名空间,第二个声明引用我们的MovieInitializer类所存在的命名空间。这两句声明的代码如下

using System.Data.Entity.Database;  // DbDatabase.SetInitialize
using MvcMovie.Models;              // MovieInitializer

接下来寻找到Application_Start方法,在该方法的开头追加一个DbDatabase.SetInitializer()方法,代码如下:

protected void Application_Start()
{
DbDatabase.SetInitializer<MovieDBContext>(new MovieInitializer());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

我们追加的DbDatabase.SetInitializer方法将会在实际使用的数据库中的结构与我们的Movie模型类所映射的数据库结构不匹配时自动重建该数据库,并且自动添加MovieInitializer类中所指定的默认数据。(很残暴的清除了用户数据)

关闭Global.asax文件重新运行我们的应用程序,并在浏览器中输入“http://localhost:xx/Movies”。当我们的应用程序启动的时候,会自动发现数据模型类结构与数据库结构不再匹配,于是删除并重建该数据库使之相匹配,然后自动追加默认数据,浏览器中显示结果如图:

点击追加按钮进行数据的追加

点击追加按钮后,新追加的包括Rating(电影等级)字段的数据能正常追加并在电影清单画面中正常显示,如图所示:

数据模型类的改变会造成数据库重建,所以今后我们会对这个安全问题进行控制处理。

MVC神韵---你想在哪解脱!(十三)的更多相关文章

  1. MVC神韵---你想在哪解脱!(十六)

    MVC验证属性自动验证原理 也许有人会问,既然我们没有在C与V追加任何显示错误信息提示的代码,那么控制器或视图内部是如何生成这些显示错误信息提示的画面的.让我们揭开这么谜底吧!当在Movie类中追加了 ...

  2. MVC神韵---你想在哪解脱!(十五)

    在模型中添加验证规则 本节介绍如何在我们的Movie(电影)模型中添加一些验证规则,同时确认当用户使用我们的应用程序创建或编辑电影信息时将使用这些验证规则对用户输入的信息进行检查.首先,让我们在Mov ...

  3. MVC神韵---你想在哪解脱!(十八)

    数据的修改视图 首先打开Movie控制器,添加一个返回数据修改视图的Edit()方法与一个对该视图中的表单提交进行处理的Edit()方法,代码如下所示: // GET: /Movies/Edit pu ...

  4. MVC神韵---你想在哪解脱!(十七)

    实现针对数据的CRUD操作 首先,让我们来看一下如何实现一条数据的明细信息视图.为了更好地体会这一功能,首先我们在前文所述的电影清单视图(Views文件夹下面的Movies文件夹下面的Index.cs ...

  5. MVC神韵---你想在哪解脱!(十四)

    修正票价字段的精度 前面我们追加数据的时候遗留下来一个问题,就是在追加数据的时候,票价(Price)字段中输入的是9.99元,但是电影清单显示画面中该数据的票价字段显示为10元,这是为什么?这个问题发 ...

  6. MVC神韵---你想在哪解脱!(十二)

    追加一条电影信息 运行应用程序,在浏览器中输入“http://localhost:xx/Movies/Create”,在表单中输入一条电影信息,然后点击追加按钮,如图所示. 点击追加按钮进行提交,表单 ...

  7. MVC神韵---你想在哪解脱!(十一)

    为了实现这一处理,我们需要在MoviesController类中追加第二个Create方法.这个Create方法具有一个[HttpPost]属性,它意味着我们将要用它来处理提交到“/Movies/Cr ...

  8. MVC神韵---你想在哪解脱!(十)

    增加追加数据的方法和视图 现在我们将要在数据库中追加并保存一些数据.我们将要创建一个表单以及一些表单输入控件,用来输入数据信息.当用户提交表单时将把这些用户输入的信息保存在数据库中.我们可以通过在浏览 ...

  9. Code First 更新数据库结构(简单实现方法:会删除原来的数据)

    之前在 http://www.cnblogs.com/mmcmmc/p/3833265.html 写到关于“Code First 更新数据库结构”的东西. 可是由于某种原因,新手们会出现各种问题,好了 ...

随机推荐

  1. 1493: [NOI2007]项链工厂

    线段树. 真还就是个线段树.. 除去操作1,2的话,线段树很容易就处理了,问题在于如何处理操作1和2.(这点没想到).. 我们用一个delta维护操作1,如果没有旋转就+k,不然就-k. 每次读入i和 ...

  2. UVa 10868 (物理) Bungee Jumping

    题意: 有个人在蹦极,给出悬崖的高度,绳子的长度,弹簧绳的胡克系数 以及 人的质量. 判断人是否能够着地,能的话是否能安全着地.所谓安全着地就是到达地面的速度不超过10m/s. 分析: 学过一点高中物 ...

  3. svn 提交失败 更新失败 提示 已经锁定

      出现问题的原因:在上传的时候,由于网络掉线,导致svn提交到一半就没有反应了,这个时候我点击了取消,再之后无论是进行 更新还是提交,都提示 已经锁定 解决方法:在项目的空白地方,点击SVN  清理 ...

  4. (转)HTTP协议详解

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  5. UVa 11292 The Dragon of Loowater 勇者斗恶龙

    你的王国里有一条n个头的恶龙,你希望雇佣一些骑士把它杀死(也就是砍掉所有的头).村里有m个骑士可以雇佣,一个能力值为 x 的骑士可以砍掉恶龙一个直径不超过 x 的头,且需要支付 x 个金币.如何雇佣骑 ...

  6. Chromuim开发机配置

    一个出色的程序员需要一台给力的电脑. 之前使用ThinkPad R400笔记本编译Chromium,确实太痛苦了,第一次编译未使用SSD,超过了24小时都没有编译完.后来断断续续折腾了将近一个月才编译 ...

  7. IOS UINavigationController 操作相关集合

    1.修改中间Title字体以及大小 [self.navigationController.navigationBar setTitleTextAttributes:[NSDictionary dict ...

  8. 《Python 学习手册4th》 第九章 元组、文件及其他

    ''' 时间: 9月5日 - 9月30日 要求: 1. 书本内容总结归纳,整理在博客园笔记上传 2. 完成所有课后习题 注:“#” 后加的是备注内容 (每天看42页内容,可以保证月底看完此书) “重点 ...

  9. Chrome的网络调试

    F12 然后

  10. void、void*以及NULL

    void.void*以及NULL 写在前面 在使用C++的过程中,void和NULL用到的频率挺高的,但是从来没有去探索过这两个关键字的联系和区别,也没有对它们做更多的探索.对于void*,说实话,实 ...