通过


使用 Visual Studio ASP.NET Web 部署:准备数据库部署

下载入门项目

本教程系列介绍如何使用 Visual Studio 2012 或 Visual Studio 2010 将 ASP.NET Web 应用程序部署到 Azure 应用服务 Web 应用或第三方托管提供程序。 有关该系列的信息,请参阅 该系列中的第一个教程

概述

本教程介绍如何让项目准备好进行数据库部署。 必须将应用程序的两个数据库中的数据库结构和部分(并非所有)数据部署到测试、暂存和生产环境。

通常,在开发应用程序时,将测试数据输入到不想部署到实时站点的数据库。 但是,你可能还需要部署一些生产数据。 在本教程中,你将配置 Contoso University 项目并准备 SQL 脚本,以便在部署时包含正确的数据。

提醒:如果在完成本教程时收到错误消息或某些内容不起作用,请务必检查 故障排除页面

SQL Server Express LocalDB(本地数据库)

示例应用程序使用 SQL Server Express LocalDB。 SQL Server Express 是 SQL Server 的免费版本。 它通常在开发期间使用,因为它基于与完整版本的 SQL Server 相同的数据库引擎。 可以使用 SQL Server Express 进行测试,并确保应用程序在生产环境中的行为相同,但 SQL Server 版本之间不同功能存在一些例外情况。

LocalDB 是 SQL Server Express 的特殊执行模式,可用于将数据库用作 .mdf 文件。 通常,LocalDB 数据库文件保存在 Web 项目的 App_Data 文件夹中。 SQL Server Express 中的用户实例功能还可用于处理 .mdf 文件,但用户实例功能已弃用;因此,建议使用 LocalDB 来处理 .mdf 文件。

通常,SQL Server Express 不用于生产 Web 应用程序。 特别不推荐将 LocalDB 用于 Web 应用程序,因为它并不是为与 IIS 兼容而设计的。

在 Visual Studio 2012 中,LocalDB 默认随 Visual Studio 一起安装。 在 Visual Studio 2010 和早期版本中,SQL Server Express(不含 LocalDB)默认随 Visual Studio 一起安装;这就是在本 系列的第一个教程中将其安装为先决条件之一的原因。

有关 SQL Server 版本(包括 LocalDB)的详细信息,请参阅以下 使用 SQL Server 数据库的资源。

实体框架和通用提供程序

对于数据库访问,Contoso University 应用程序需要以下必须随应用程序一起部署的软件,因为它不包括在 .NET Framework 中:

由于此软件包含在 NuGet 包中,因此已设置项目,以便随项目一起部署所需的程序集。 (链接指向这些包的当前版本,这些版本可能比您为本教程下载的初学者项目中安装的版本更新。)

如果要部署到第三方托管提供程序而不是 Azure,请确保使用 Entity Framework 5.0 或更高版本。 早期版本的 Code First 迁移需要完全信任,并且大多数托管提供程序将在中等信任中运行应用程序。 有关 Medium Trust 的详细信息,请参阅“作为测试环境部署到 IIS”教程。

配置 Code First 迁移以用于部署应用程序数据库

Contoso University 应用程序数据库由 Code First 管理,你将使用 Code First 迁移来部署它。 有关使用 Code First 迁移的数据库部署的概述,请参阅 本系列中的第一个教程

部署应用程序数据库时,通常您不会直接将开发数据库与其中所有的数据部署到生产环境,因为其中的许多数据可能仅用于测试用途。 例如,测试数据库中的学生姓名是虚构的。 另一方面,通常不能仅仅部署一个完全没有数据的数据库结构。 测试数据库中的某些数据可能是实际数据,并且用户开始使用该应用程序时必须存在。 例如,数据库可能有一个包含有效成绩值或真实部门名称的表。

要想实现此常见方案,需要配置一个 Code First Migrations Seed 方法,该方法只向数据库插入你希望在生产环境中存在的数据。 此方法 Seed 不应插入测试数据,因为它将在 Code First 在生产中创建数据库后在生产环境中运行。

迁移功能发布之前的早期 Code First 版本中,人们通常会使用 Seed 方法插入测试数据,因为在开发过程中,每次模型更改时,数据库必须从头开始完全重建。 使用 Code First 迁移时,测试数据会在数据库更改后保留,因此不需要在方法中包含 Seed 测试数据。 下载的项目使用了一种方法,将所有数据包含在一个初始值设定项类的 Seed 方法中。 在本教程中,你将禁用该初始化类,并启用迁移功能。 然后,你将更新 Seed Migrations 配置类中的方法,以便它仅插入要在生产环境中插入的数据。

下图说明了应用程序数据库的架构:

学校_数据库_示意图

对于这些教程,假设在首次部署站点时,StudentEnrollment 表应为空。 其他表包含必须在应用程序上线时预加载的数据。

禁用初始值设定项

由于将使用 Code First Migrations,因此无需使用 DropCreateDatabaseIfModelChanges Code First 初始化。 此初始值设定项的代码位于 ContosoUniversity.DAL 项目中 的 SchoolInitializer.cs 文件中。 每当应用程序首次尝试访问数据库时,appSettings 文件的元素中的设置会导致此初始值设定项运行:

<appSettings>
  <add key="Environment" value="Dev" />
  <add key="DatabaseInitializerForType ContosoUniversity.DAL.SchoolContext, ContosoUniversity.DAL" value="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity.DAL" />
</appSettings>

打开应用程序 Web.config 文件,删除或注释掉 add 指定 Code First 初始值设定项类的元素。 元素 appSettings 现在如下所示:

<appSettings>
  <add key="Environment" value="Dev" />
</appSettings>

注释

指定初始值设定项类的另一种方法是在 Global.asax 文件中的 Application_Start 方法中调用 Database.SetInitializer。 如果要在使用该方法指定初始化程序的项目中启用迁移,请删除该代码行。

注释

如果使用 Visual Studio 2013,请在步骤 2 和步骤 3 之间添加以下步骤:(a) 在 PMC 中输入“update-package entityframework -version 6.1.1”以获取 EF 的当前版本。 然后(b)编译项目以获取编译错误列表,并修复它们。 删除那些不再存在的命名空间相关的 using 语句,右键单击并选择“解析”来添加需要的 using 语句,并将 System.Data.EntityState 修改为 System.Data.Entity.EntityState。

启用 Code First 迁移

  1. 确保将 ContosoUniversity 项目(而不是 ContosoUniversity.DAL)设为启动项目。 在 解决方案资源管理器中,右键单击 ContosoUniversity 项目,然后选择“ 设置为启动项目”。 Code First Migrations 将在启动项目中查找数据库连接字符串。

  2. “工具”菜单中,选择“NuGet 包管理器>控制台”。

    Selecting_Package_Manager_Console

  3. “包管理器控制台” 窗口顶部,选择 ContosoUniversity.DAL 作为默认项目,然后在提示符 PM> 下输入“enable-migrations”。

    enable-migrations 命令

    (如果收到一条错误信息显示无法识别 enable-migrations 命令,请输入命令 update-package EntityFramework -Reinstall,然后再次尝试。)

    此命令在 ContosoUniversity.DAL 项目中创建 迁移 文件夹,并将该文件放入该文件夹两个文件:一个可用于配置迁移 的Configuration.cs 文件,以及用于创建数据库的第一个迁移的 InitialCreate.cs 文件。

    迁移文件夹

    包管理器控制台的默认项目下拉列表中选择了 DAL 项目,因为enable-migrations必须在包含 Code First 上下文类的项目中执行该命令。 当该类位于类库项目中时,Code First Migrations 在解决方案的启动项目中查找数据库连接字符串。 在 ContosoUniversity 解决方案中,Web 项目已设置为启动项目。 如果不想将连接字符串指定为 Visual Studio 中的启动项目,可以在 PowerShell 命令中指定启动项目。 若要查看命令语法,请输入命令 get-help enable-migrations

    enable-migrations 命令会自动创建第一个迁移,因为数据库已存在。 另一种方法是让迁移工具创建数据库。 为此,在启用迁移之前,请使用 服务器资源管理器SQL Server 对象资源管理器 删除 ContosoUniversity 数据库。 启用迁移后,输入命令“add-migration InitialCreate”手动创建第一个迁移。 然后,可以通过输入命令“update-database”来创建数据库。

设置种子方法

在本教程中,你将通过在 Code First Migrations 类的Configuration方法中添加代码Seed来添加固定数据。 每次迁移后,Code First 迁移都会调用 Seed 该方法。

Seed由于该方法在每次迁移后运行,因此第一次迁移后表中已存在数据。 若要处理这种情况,你将使用 AddOrUpdate 该方法更新已插入的行,或插入它们(如果尚不存在)。 您的场景中,AddOrUpdate 方法可能不是最佳选择。 有关详细信息,请参阅 Julie Lerman 博客上的 EF 4.3 AddOrUpdate 方法

  1. 打开 Configuration.cs 文件,并将方法中的 Seed 注释替换为以下代码:

    var instructors = new List<Instructor>
    {   
        new Instructor { FirstMidName = "Kim",     LastName = "Abercrombie", HireDate = DateTime.Parse("1995-03-11"), OfficeAssignment = new OfficeAssignment { Location = "Smith 17" } },
        new Instructor { FirstMidName = "Fadi",    LastName = "Fakhouri",    HireDate = DateTime.Parse("2002-07-06"), OfficeAssignment = new OfficeAssignment { Location = "Gowan 27" } },
        new Instructor { FirstMidName = "Roger",   LastName = "Harui",       HireDate = DateTime.Parse("1998-07-01"), OfficeAssignment = new OfficeAssignment { Location = "Thompson 304" } },
        new Instructor { FirstMidName = "Candace", LastName = "Kapoor",      HireDate = DateTime.Parse("2001-01-15") },
        new Instructor { FirstMidName = "Roger",   LastName = "Zheng",       HireDate = DateTime.Parse("2004-02-12") }
    };
    instructors.ForEach(s => context.Instructors.AddOrUpdate(i => i.LastName, s));
    context.SaveChanges();
    
    var departments = new List<Department>
    {
        new Department { Name = "English",     Budget = 350000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 1 },
        new Department { Name = "Mathematics", Budget = 100000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 2 },
        new Department { Name = "Engineering", Budget = 350000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 3 },
        new Department { Name = "Economics",   Budget = 100000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 4 }
    };
    departments.ForEach(s => context.Departments.AddOrUpdate(d => d.Name, s));
    context.SaveChanges();
    
    var courses = new List<Course>
    {
        new Course { CourseID = 1050, Title = "Chemistry",      Credits = 3, DepartmentID = 3 },
        new Course { CourseID = 4022, Title = "Microeconomics", Credits = 3, DepartmentID = 4 },
        new Course { CourseID = 4041, Title = "Macroeconomics", Credits = 3, DepartmentID = 4 },
        new Course { CourseID = 1045, Title = "Calculus",       Credits = 4, DepartmentID = 2 },
        new Course { CourseID = 3141, Title = "Trigonometry",   Credits = 4, DepartmentID = 2 },
        new Course { CourseID = 2021, Title = "Composition",    Credits = 3, DepartmentID = 1 },
        new Course { CourseID = 2042, Title = "Literature",     Credits = 4, DepartmentID = 1 }
    };
    courses.ForEach(s => context.Courses.AddOrUpdate(s));
    context.SaveChanges();
    
    courses[0].Instructors.Add(instructors[0]);
    courses[0].Instructors.Add(instructors[1]);
    courses[1].Instructors.Add(instructors[2]);
    courses[2].Instructors.Add(instructors[2]);
    courses[3].Instructors.Add(instructors[3]);
    courses[4].Instructors.Add(instructors[3]);
    courses[5].Instructors.Add(instructors[3]);
    courses[6].Instructors.Add(instructors[3]);
    context.SaveChanges();
    
  2. List 引用下方带有红色波浪线,因为其命名空间尚未存在 using 语句。 右键单击其中一个实例 List 并单击“ 解析”,然后单击 “使用 System.Collections.Generic”。

    使用 using 语句解决

    此菜单选择将以下代码添加到 using 文件顶部附近的语句。

    using System.Collections.Generic;
    
  3. 按 CTRL-SHIFT-B 生成项目。

项目现已准备好部署 ContosoUniversity 数据库。 部署应用程序后,首次运行该应用程序并导航到访问数据库的页面时,Code First 将创建数据库并运行此方法 Seed

注释

向该方法添加代码 Seed 是可以将固定数据插入数据库中的许多方法之一。 另一种方法是向每个迁移类的Up方法和Down方法添加代码。 和UpDown方法包含实现数据库更改的代码。 你将在 “部署数据库更新 ”教程中看到这些示例。

还可以编写使用 Sql 该方法执行 SQL 语句的代码。 例如,如果要将“预算”列添加到“部门”表,并且想要将所有部门预算初始化为 $1,000.00 作为迁移的一部分,则可以将以下代码行添加到 Up 该迁移的方法:

Sql("UPDATE Department SET Budget = 1000");

为成员身份数据库部署创建脚本

Contoso University 应用程序使用 ASP.NET 成员身份系统和表单身份验证对用户进行身份验证和授权。 只有处于管理员角色的用户才能访问 “更新额度 ”页。

运行应用程序并单击“ 课程”,然后单击“ 更新额度”。

单击“更新额度”

此时会显示 “登录 ”页,因为 “更新信用额度 ”页需要管理权限。

输入 管理员 作为用户名, 并将 devpwd 作为密码,然后单击“ 登录”。

登录页

此时会显示 “更新信用额度 ”页。

更新致谢页

用户和角色信息位于由 Web.config 文件中 DefaultConnection 连接字符串指定的 aspnet-ContosoUniversity 数据库中。

此数据库不由 Entity Framework Code First 管理,因此无法使用迁移来部署它。 你将使用 dbDacFx 提供程序部署数据库架构,并将发布配置文件配置为运行脚本,该脚本将初始数据插入数据库表。

注释

Visual Studio 2013 引入了新的 ASP.NET 成员身份系统(现已命名为 ASP.NET 标识)。 使用新系统可将应用程序和成员身份表保留在同一数据库中,并且可以使用 Code First 迁移来部署这两个表。 示例应用程序使用早期 ASP.NET 成员身份系统,无法使用 Code First 迁移来部署系统。 部署此成员身份数据库的过程也适用于应用程序需要部署未由 Entity Framework Code First 创建的 SQL Server 数据库的任何其他方案。

在这里,你通常不希望在生产环境中使用与开发相同的数据。 首次部署站点时,通常会排除为测试创建的大多数或全部用户帐户。 因此,下载的项目有两个成员身份数据库:aspnet-ContosoUniversity.mdf 包含开发用户和 aspnet-ContosoUniversity-Prod.mdf 包含生产用户。 在本教程中,用户名在两个数据库中相同: 管理员 和非 admin。 两个用户在开发数据库中都有密码 devpwd,在生产数据库中有密码 prodpwd

你将开发用户部署到测试环境,并将生产用户部署到预生产环境和生产环境。 为此,你将在本教程中创建两个 SQL 脚本,一个用于开发和一个用于生产,在后面的教程中,你将配置发布过程以运行它们。

注释

成员身份数据库存储帐户密码的哈希。 若要将帐户从一台计算机部署到另一台计算机,必须确保哈希例程不会在目标服务器上生成不同于源计算机上的哈希。 使用 ASP.NET 通用提供程序时,它们将生成相同的哈希,前提是不更改默认算法。 默认算法HMACSHA256,并在 Web.config 文件中 machineKey 元素的验证属性中指定。

可以使用 SQL Server Management Studio(SSMS)或使用第三方工具手动创建数据部署脚本。 本教程的余下部分将演示如何在 SSMS 中执行此操作,但如果不想安装和使用 SSMS,则可以从项目的完整版本获取脚本,并跳到在解决方案文件夹中存储这些脚本的部分。

若要安装 SSMS,请从 下载中心安装它:Microsoft SQL Server 2012 Express ,方法是单击 ENU\x64\SQLManagementStudio_x64_ENU.exeENU\x86\SQLManagementStudio_x86_ENU.exe。 如果你为系统选择错误的选项,将导致安装失败,你可以尝试其他选项。

(请注意,这是 600 兆字节的下载。安装可能需要很长时间,并且需要重启计算机。

在 SQL Server 安装中心的第一页上,单击“ 新建 SQL Server 独立安装”或向现有安装添加功能,并按照说明操作,接受默认选项。

创建开发数据库脚本

  1. 运行 SSMS。

  2. 在“ 连接到服务器 ”对话框中,输入 (localdb)\v11.0 作为 服务器名称,保留“ 身份验证 ”设置为 Windows 身份验证,然后单击“ 连接”。

    SSMS 连接到服务器

  3. “对象资源管理器” 窗口中,展开 “数据库”,右键单击 aspnet-ContosoUniversity,单击“ 任务”,然后单击“ 生成脚本”。

    SSMS 生成脚本

  4. 在“ 生成和发布脚本 ”对话框中,单击“ 设置脚本选项”。

    可以跳过 “选择对象” 步骤,因为默认值是 脚本整个数据库和所有数据库对象 ,这就是所需的。

  5. 单击 “高级”

    SSMS 脚本选项

  6. 在“ 高级脚本选项 ”对话框中,向下滚动到 要脚本的数据类型,然后单击下拉列表中的 “仅数据 ”选项。

  7. 脚本 USE DATABASE 更改为 False。 USE 语句对 Azure SQL 数据库无效,在测试环境中不需要部署到 SQL Server Express。

    仅 SSMS 脚本数据,无 USE 语句

  8. 单击 “确定”

  9. 在“ 生成和发布脚本 ”对话框中, “文件名 ”框指定脚本的创建位置。 将解决方案文件夹的路径(包含ContosoUniversity.sln文件的文件夹)和文件名更改为 aspnet-data-dev.sql

  10. 单击“ 下一步 ”转到 “摘要 ”选项卡,然后单击“ 下一步 ”以创建脚本。

    创建的 SSMS 脚本

  11. 单击“完成”。

创建生产数据库脚本

由于您尚未使用生产数据库运行项目,因此它尚未附加到 LocalDB 实例。 因此,需要先附加数据库。

  1. 在 SSMS 对象资源管理器中,右键单击 “数据库 ”,然后单击“ 附加”。

    SSMS 附加

  2. 在“附加数据库”对话框中,单击“添加”,然后导航到App_Data文件夹中的aspnet-ContosoUniversity-Prod.mdf文件。

    SSMS 添加 .mdf 文件进行附加

  3. 单击 “确定”

  4. 按照前面用于为生产文件创建脚本的相同过程操作。 将脚本文件命名 为aspnet-data-prod.sql

总结

这两个数据库现已准备好部署,解决方案文件夹中有两个数据部署脚本。

数据部署脚本

在以下教程中,将配置影响部署的项目设置,并为部署的应用程序中必须不同的设置设置自动 Web.config 文件转换。

详细信息

有关 NuGet 的详细信息,请参阅使用 NuGet 和 NuGet 文档管理项目库 如果不想使用 NuGet,则需要了解如何分析 NuGet 包,以确定它在安装时执行的操作。 (例如,它可以配置 Web.config 转换、将 PowerShell 脚本配置为在生成时运行等)若要详细了解 NuGet 的工作原理,请参阅 创建和发布包配置文件和源代码转换