1. 综述
不管什么时候,程序都有可能像代码更新一样更新数据库。本章节你将进行数据库修改,测试,然后部署到测试环境和生产环境。
提醒:如果根据本章节所做的操作出现错误信息或一些功能不正常的话,请务必check Troubleshooting页面。
2. 给表添加新列
本小节,将修改Student和Instructor实体共同的基类Person类,添加一个birth date字段,也要在展示页面的表格上添加一个新列。
在ContosoUniversity.DAL项目,打开Person.cs在类的末尾添加如下的代码属性(记得,大括号里面哦)。
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Required(ErrorMessage = "Birth date is required.")]
[Display(Name = "Birth Date")]
public DateTime? BirthDate { get; set; }
需要更新初始化类来支持新列,打开SchoolInitializer.cs文件找到var students = new List<Student>
开头的代码,替换成包括
birth date信息的如下的爱吗:
var students = new List<Student>
{
new Student { FirstMidName = "Carson", LastName = "Alexander", EnrollmentDate = DateTime.Parse("2005-09-01"), BirthDate = DateTime.Parse("1990-01-01") },
new Student { FirstMidName = "Meredith", LastName = "Alonso", EnrollmentDate = DateTime.Parse("2002-09-01"), BirthDate = DateTime.Parse("1989-01-15") },
new Student { FirstMidName = "Arturo", LastName = "Anand", EnrollmentDate = DateTime.Parse("2003-09-01"), BirthDate = DateTime.Parse("1988-02-01") },
new Student { FirstMidName = "Gytis", LastName = "Barzdukas", EnrollmentDate = DateTime.Parse("2002-09-01"), BirthDate = DateTime.Parse("1987-03-15") },
new Student { FirstMidName = "Yan", LastName = "Li", EnrollmentDate = DateTime.Parse("2002-09-01"), BirthDate = DateTime.Parse("1985-11-11") },
new Student { FirstMidName = "Peggy", LastName = "Justice", EnrollmentDate = DateTime.Parse("2001-09-01"), BirthDate = DateTime.Parse("1970-11-21") },
new Student { FirstMidName = "Laura", LastName = "Norman", EnrollmentDate = DateTime.Parse("2003-09-01"), BirthDate = DateTime.Parse("1992-10-11") },
new Student { FirstMidName = "Nino", LastName = "Olivetto", EnrollmentDate = DateTime.Parse("2005-09-01"), BirthDate = DateTime.Parse("1986-06-06") }
};
将var instructors = new List<Instructor>
开头的代码块替换成如下代码:
var instructors = new List<Instructor>
{
new Instructor { FirstMidName = "Kim", LastName = "Abercrombie", HireDate = DateTime.Parse("1995-03-11"), BirthDate = DateTime.Parse("1918-08-12") },
new Instructor { FirstMidName = "Fadi", LastName = "Fakhouri", HireDate = DateTime.Parse("2002-07-06"), BirthDate = DateTime.Parse("1960-03-15") },
new Instructor { FirstMidName = "Roger", LastName = "Harui", HireDate = DateTime.Parse("1998-07-01"), BirthDate = DateTime.Parse("1970-01-11") },
new Instructor { FirstMidName = "Candace", LastName = "Kapoor", HireDate = DateTime.Parse("2001-01-15"), BirthDate = DateTime.Parse("1975-04-11") },
new Instructor { FirstMidName = "Roger", LastName = "Zheng", HireDate = DateTime.Parse("2004-02-12"), BirthDate = DateTime.Parse("1957-10-12") }
};
在ContosoUniversity项目打开Instructors.aspx文件,添加一个模板字段来显示birth date,在hire date和office assignment字段之间:
<asp:TemplateField HeaderText="Birth Date" SortExpression="BirthDate">
<ItemTemplate>
<asp:Label ID="InstructorBirthDateLabel" runat="server" Text='<%# Eval("BirthDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="InstructorBirthDateTextBox" runat="server" Text='<%# Bind("BirthDate", "{0:d}") %>'
Width="7em"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
(注:如果代码变形了,可以通过CTRL+K+D来格式化代码)
在Students.aspx文件,在enrollment date 之前添加一个dynamic字段显示birth date:
<asp:DynamicField DataField="BirthDate" HeaderText="Birth Date" SortExpression="BirthDate"/>
在StudentsAdd.aspx页面, enrollment date之前添加一个bound字段显示birth date:
<asp:BoundField DataField="BirthDate" HeaderText="Birth Date"
SortExpression="BirthDate"/>
在BLL\SchoolBL.cs文件, 支持按列排序的GetStudents
方法力的switch
语句里的default语句之前,添加一个case分支以支持使用birth date排序:
case "BirthDate":
students = students.OrderBy(s => s.BirthDate);
break;
case "BirthDate DESC":
students = students.OrderByDescending(s => s.BirthDate);
break;
运行程序访问Students页面,你可能感觉有一点慢,那是因为Entity Framework探测到了model变了,需要删除并重建数据库,然后将初始化里的数据插入到数据库。页面加载以后,可以看到有了一个birth date新列。
访问Add Students和Instructors页面验证是否有这个新列。
3. 部署数据库更新到测试环境
在生产环境,部署升级的时候需要保持以前的数据,但是在测试环境则没有必要,不过为了使部署步骤和生产环境部署一样,我们还是在测试环境保存以前的数据,以便部署步骤尽量一样。对于生产环境,下面列出了一些需要follow的步骤:(忽略app_offline.htm步骤):
从生产环境将School-Prod.sdf下载下来,放到Visual Studio项目的App_Data目录
手工改变schema更新,手工更新数据
重新上传School-Prod.sdf到生产环境
部署项目
(除了手工上传的方式,也可以使用和项目一起部署的方式,但是需要在项目属性里设置部署的时候将这个数据库也一起部署了(membership数据库除外),手工方式的好处是不用修改任何设置,依然可以使用之前的one-click发布设置。)
应用Schema修改
部署到册数环境,你不必担心是否能获得最新的copy,可以更新项目里下载下来的School-Prod.sdf来用。
看看Entity Framework里为School数据库做的修改,你可以手工修改测试环境和生产环境数据库。在Solution Explorer里双击App_Data\School.sdf在Server Explorer里打开数据库连接。
在Server Explorer里展开School-Dev.sdf,展开Tables-> Person->Columns。你可以看到Code First 生产的BirthDate列:
在Properties窗口,你可以看到BirthDate列的数据类型是datetime, 名称和数据类型是唯一需要修改的。
在Server Explorer里,右键School-Dev.sdf数据库然后选择关闭连接Close Connection。
(这只是数据库更新的简单例子,在真实环境里,数据库修改很麻烦的。本章的重点不是修改或跟踪数据库变化,而是数据库改变怎么影响数据库部署过程。普通的步骤就是:数据模型改变以后数据库需要怎么改变,以及Code First怎么自动更新数据库的,然后再用手工方式去做。)
下一步是手工修改School-Prod.sdf文件
在Server Explorer里,展开School-Prod.sdf->Tables->Person->Columns,然后你可以看到老的表结构(没有BirthDate列)。
右键Person选择Edit Table Schema显示Edit Table对话框。
在Edit Table对话框,在Discriminator下面添加一个新列,输入如下信息:
Column Name: BirthDate Data Type: datetime
Length, Allow Nulls, Unique和Primary Key的默认值都没问题。点击OK。
数据库和新代码能够很好的一起运行了,但是BirthDate
列在测试数据库(后面的生产环境数据库)的位置和在Entity Framework Code First 里的位置是不一样的,因为Visual Studio tool for SQL Server Compact 只支持在最下面添加新列。其实,说实话只是顺序不一样而已,没有什么大的问题。
在数据库方面,Visual Studio tool for SQL Server Compact 可能还会有其他的一些限制不能和Code First.的自动生产功能一样,你可以通过如下的方式来改进:
- 使用WebMatrix的数据库操作功能,比Visual Studio 下的SQL Server Compact 的工具功能多。
- 使用第三方或者开源工具,例如CodePlex 上的SQL Server Compact Toolbox 和 SQL Compact data and schema script utility。
- 自己写DDL(数据定义语言)脚本来维护数据库结构。
- 迁移至SQL Server Express或完整版SQL Server以后,可是使用SQL Server Management Studio,使用完整的数据库维护功能,也可以使用Visual Studio 2010 SQL Server database projects 或者 Database Publishing Wizard 来自动生产脚本(可能还有其它的原因迁移至SQL Server,请看第2章节里的叙述)。
- 使用Entity Framework Code First Migrations,自动更新新的数据库以匹配新的数据模型。本章节撰写之前,该工具还没用Release,不过可是使用NuGet来安装预览器,请参看Entity Framework team blog。
更新数据
测试数据库的结果和新代码吻合了,但是你需要添加instructor 们的生日进去,你可以手工创建并执行一个SQL脚本。本章节已经帮你创建了这个脚本,你可以运行它。
Server Explorer里, 右键School-Prod.sdf库的Person表,选择New Query。
如果出现Add Table对话框的话,关闭它,然后将下面的SQL脚本复制到查询窗口的SQL窗格里:
UPDATE Person SET BirthDate = '1918-08-12' WHERE PersonID = 9;
UPDATE Person SET BirthDate = '1960-03-15' WHERE PersonID = 10;
UPDATE Person SET BirthDate = '1970-01-11' WHERE PersonID = 11;
UPDATE Person SET BirthDate = '1975-04-11' WHERE PersonID = 12;
UPDATE Person SET BirthDate = '1957-10-12' WHERE PersonID = 13;
右键SQL窗格,选择Execute SQL。
如果出现Query Definitions Differ对话框,点击Continue继续。该消息只是告诉你查询代码不能直观里表示在SQL窗格上面UI及时显示界面上。
查询运行了,然后弹出了5条数据被更新的确认窗口。
Server Explorer里,重新右键Person选择Show Table Data检查instructors是否都有了生日数据。
测试数据库现在可以部署了。
复制数据库到测试站点
在Windows Explorer资源管理器里,将ContosoUniversity项目的App_Data文件夹里的School-Prod.sdf文件复制到测试站点的App_Data目录(C:\inetpub\wwwroot\contosouniversity\App_Data),覆盖原来的数据库文件。
和数据库更新一起部署更新代码
可以部署更新的代码了, Solution Configurations下来菜单里选择Test, Publish profile 里也选择Test。点击Publish Web。(如果由于自定义了工具栏操作不了的话,参考:第8章节的内容)。
Visual Studio部署了修改后的程序,并在Output窗口显示了成功信息。
运行程序http://localhost/contosouniversity来验证更新是否成功部署,在Instructors 页面可以看到真实的birth date了。
也可以运行Students页面 和Add Students页面来验证更新是否成功。
4. 部署数据库更新到生产环境
现在可以部署到生产环境了。除了需要先上传app_offline.htm文件防止用户使用站点以外,其它步骤和部署测试环境是一样的。生产环境部署的步骤如下:
- 上传app_offline.htm文件到生产环境站点
- 从生产环境站点下载School-Prod.sdf文件保存到本机的App_Data文件夹,然后再备份一份(见下面的注释)。
- 手工添加新列
- 运行更新脚本(具体更新数据视真实环境需要而定)
- 上传School-Prod.sdf文件到生产环境站点
- 使用Visual Studio发布
注释:数据库备份的话题就不多说了,肯定是需要经常备份的,这里指的是School-Prod.sdf 和aspnet-Prod.sdf文件。
最后一步和部署code-only 更新是一样的。在Solution Configurations下拉菜单里选择Release,在Publish profile下拉菜单里选择Production,然后点击Publish Web。
Visual Studio部署了修改后的程序,并在Output窗口显示了成功信息。
验证是否正确部署之前,需要先删除app_offline.htm文件,删除以后,就可以运行站点来验证部署是否正常了。
现在,你已经成功将包含数据库更新的应用程序部署到测试环境和生产环境了。下一章节讲的是如何将SQL Server Compact数据库迁移到SQL Server Express 或者完整版SQL Server上。