• 微软ASP.NET站点部署指南(9):部署数据库更新


    1.  综述

    不管什么时候,程序都有可能像代码更新一样更新数据库。本章节你将进行数据库修改,测试,然后部署到测试环境和生产环境。

    提醒:如果根据本章节所做的操作出现错误信息或一些功能不正常的话,请务必check Troubleshooting页面

    2.  给表添加新列

    本小节,将修改StudentInstructor实体共同的基类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 StudentsInstructors页面验证是否有这个新列。

    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.sdfServer 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, UniquePrimary Key的默认值都没问题。点击OK

    数据库和新代码能够很好的一起运行了,但是BirthDate 列在测试数据库(后面的生产环境数据库)的位置和在Entity Framework Code First 里的位置是不一样的,因为Visual Studio tool for SQL Server Compact 只支持在最下面添加新列。其实,说实话只是顺序不一样而已,没有什么大的问题。

    在数据库方面,Visual Studio tool for SQL Server Compact 可能还会有其他的一些限制不能和Code First.的自动生产功能一样,你可以通过如下的方式来改进:

    更新数据

    测试数据库的结果和新代码吻合了,但是你需要添加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下来菜单里选择TestPublish 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.sdfaspnet-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上。

  • 相关阅读:
    男子胃脘胀痛案(知老)
    转 Django中的Form
    转 Alert.log shows No Standby Redo Logfiles Of Size 153600 Blocks Available
    转发 django 初探
    转 Logs are not shipped to the physical standby database
    python 之django (一) Windows环境下Django 1.6.11开发环境搭建(简易版)
    oracle db 产品路线图
    转 python中%s与%d
    转 python 的常用函数replace, split(),enumerate() 函数
    转 [Error]EOL while scanning string literal
  • 原文地址:https://www.cnblogs.com/TomXu/p/2263167.html
Copyright © 2020-2023  润新知