在 ASP.NET MVC 应用程序中对实体框架进行排序、筛选和分页 (3,共 10 个)

作者 :Tom Dykstra

Contoso University 示例 Web 应用程序演示如何使用 Entity Framework 5 Code First 和 Visual Studio 2012 创建 ASP.NET MVC 4 应用程序。 若要了解教程系列,请参阅本系列中的第一个教程

注意

如果遇到无法解决的问题, 请下载已完成的章节 并尝试重现问题。 通常可以通过将代码与已完成的代码进行比较来找到问题的解决方案。 有关一些常见错误及其解决方法,请参阅 错误和解决方法。

在上一教程中,你为实体的基本 CRUD 操作 Student 实现了一组网页。 在本教程中,你将向 “学生 索引”页添加排序、筛选和分页功能。 同时,还将创建一个执行简单分组的页面。

下图展示了完成操作后的页面外观。 列标题是用户可以单击以按该列排序的链接。 重复单击列标题可在升降排序顺序之间切换。

Students_Index_page_with_paging

若要将排序添加到“学生索引”页,需要更改 Index 控制器的 Student 方法,并将代码添加到“索引” Student 视图。

向 Index 方法添加排序功能

Controllers\StudentController.cs 中,将 方法替换为 Index 以下代码:

public ActionResult Index(string sortOrder)
{
   ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
   ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";
   var students = from s in db.Students
                  select s;
   switch (sortOrder)
   {
      case "Name_desc":
         students = students.OrderByDescending(s => s.LastName);
         break;
      case "Date":
         students = students.OrderBy(s => s.EnrollmentDate);
         break;
      case "Date_desc":
         students = students.OrderByDescending(s => s.EnrollmentDate);
         break;
      default:
         students = students.OrderBy(s => s.LastName);
         break;
   }
   return View(students.ToList());
}

此代码接收来自 URL 中的查询字符串的 sortOrder 参数。 查询字符串值由 ASP.NET MVC 作为操作方法的参数提供。 该参数将是一个字符串,可为“Name”或“Date”,可选择后跟下划线和字符串“desc”来指定降序。 默认排序顺序为升序。

首次请求索引页时,没有任何查询字符串。 学生按 升序显示, LastName这是语句中的下降案例所建立的 switch 默认值。 当用户单击列标题超链接时,查询字符串中会提供相应的 sortOrder 值。

使用这两 ViewBag 个变量,以便视图可以使用相应的查询字符串值配置列标题超链接:

ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";

这些是三元语句。 第一个指定如果 sortOrder 参数为 null 或为空, ViewBag.NameSortParm 则应设置为“name_desc”;否则,应将其设置为空字符串。 通过这两个语句,视图可如下设置列标题超链接:

当前排序顺序 姓氏超链接 日期超链接
姓氏升序 descending ascending
姓氏降序 ascending ascending
日期升序 ascending descending
日期降序 ascending ascending

方法使用 LINQ to Entities 指定要排序依据的列。 代码在 语句之前switch创建一个 IQueryable 变量,在 语句中switch对其进行修改,并在 语句后switch调用 ToList 方法。 当创建和修改 IQueryable 变量时,不会向数据库发送任何查询。 在通过调用 等ToList方法将 IQueryable 对象转换为集合之前,不会执行查询。 因此,此代码会导致在 语句之前 return View 不会执行的单个查询。

Views\Student\Index.cshtml 中,将标题行的 和 <th> 元素替换为<tr>突出显示的代码:

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm })
        </th>
        <th>First Name
        </th>
        <th>
            @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm })
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {

此代码使用属性中 ViewBag 的信息设置具有相应查询字符串值的超链接。

运行该页并单击“ 姓氏 ”和“ 注册日期” 列标题,验证排序是否正常工作。

显示 Contoso 大学生索引页的屏幕截图。列标题为“姓氏”、“名字”和“注册日期”。

单击“ 姓氏” 标题后,学生将按姓氏降序显示。

显示“Contoso 大学生索引”页的屏幕截图,其中包含按姓氏降序显示的学生列表。

将搜索框添加到“学生索引”页

要向学生索引页添加筛选功能,需将文本框和提交按钮添加到视图,并在 Index 方法中做出相应的更改。 在文本框中输入一个字符串以在名字和姓氏字段中进行搜索。

向 Index 方法添加筛选功能

Controllers\StudentController.cs 中,将 方法替换为 Index 以下代码, () 突出显示更改:

public ViewResult Index(string sortOrder, string searchString)
{
    ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
    ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
    var students = from s in db.Students
                   select s;
    if (!String.IsNullOrEmpty(searchString))
    {
        students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
                               || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
    }
    switch (sortOrder)
    {
        case "name_desc":
            students = students.OrderByDescending(s => s.LastName);
            break;
        case "Date":
            students = students.OrderBy(s => s.EnrollmentDate);
            break;
        case "date_desc":
            students = students.OrderByDescending(s => s.EnrollmentDate);
            break;
        default:
            students = students.OrderBy(s => s.LastName);
            break;
    }

    return View(students.ToList());
}

已向 Index 方法添加 searchString 参数。 还向 LINQ 语句添加了 一个 where 子句,该子句仅选择名字或姓氏包含搜索字符串的学生。 将从要添加到索引视图的文本框接收搜索字符串值。仅当存在要搜索的值时,才会执行添加 where 子句的语句。

注意

在许多情况下,可以在实体框架实体集上或作为内存中集合上的扩展方法调用相同的方法。 结果通常相同,但在某些情况下可能有所不同。 例如,方法的.NET Framework实现Contains在向该方法传递空字符串时返回所有行,但SQL Server Compact 4.0 的 Entity Framework 提供程序返回空字符串的零行。 因此,示例中的代码 (将 语句if放入 Where 语句) 可确保所有版本的 SQL Server 获得相同的结果。 此外,方法的.NET Framework实现Contains默认执行区分大小写的比较,但实体框架SQL Server提供程序默认执行不区分大小写的比较。 因此,调用 ToUpper 方法以使测试显式不区分大小写可确保以后更改代码以使用存储库时结果不会更改,后者将返回集合 IEnumerable 而不是 IQueryable 对象。 (在 IEnumerable 集合上调用 Contains 方法时,将获得 .NET Framework 实现;当在 IQueryable 对象上调用它时,将获得数据库提供程序实现。)

向“学生索引”视图添加搜索框

Views\Student\Index.cshtml 中,紧接在开始table标记前面添加突出显示的代码,以便创建描述文字、文本框和“搜索”按钮。

<p>
    @Html.ActionLink("Create New", "Create")
</p>

@using (Html.BeginForm())
{
    <p>
        Find by name: @Html.TextBox("SearchString")  
        <input type="submit" value="Search" /></p>
}

<table>
    <tr>

运行页面,输入搜索字符串,然后单击“ 搜索 ”验证筛选是否正常工作。

Students_Index_page_with_search_box

请注意,URL 不包含“an”搜索字符串,这意味着如果为此页面添加书签,则使用书签时不会获得筛选列表。 本教程稍后将更改“ 搜索 ”按钮,以便将查询字符串用于筛选条件。

将分页添加到学生索引页

若要将分页添加到“学生索引”页,请首先安装 PagedList.Mvc NuGet 包。 然后,你将在 方法中进行其他更改, Index 并将分页链接添加到 Index 视图。 PagedList.Mvc 是适用于 ASP.NET MVC 的众多良好分页和排序包之一,此处的使用只是作为示例,而不是作为其他选项的建议。 下图显示了分页链接。

显示分页链接的“学生索引”页的屏幕截图。

安装 PagedList.MVC NuGet 包

NuGet PagedList.Mvc 包会自动安装 PagedList 包作为依赖项。 PagedList 包为 IQueryableIEnumerable 和 集合安装PagedList集合类型和扩展方法。 扩展方法在 或 IEnumerable的集合IQueryable中创建PagedList单个数据页,PagedList并且集合提供了多个有助于分页的属性和方法。 PagedList.Mvc 包安装显示分页按钮的分页帮助程序。

“工具 ”菜单中,选择“ NuGet 包管理器 ”,然后选择 “管理解决方案的 NuGet 包”。

“管理 NuGet 包 ”对话框中,单击左侧的“ 联机 ”选项卡,然后在搜索框中输入“分页”。 看到 PagedList.Mvc 包时,单击“ 安装”。

显示“管理 N u GET 包”对话框的屏幕截图。突出显示了“联机”选项卡和填充了“分页”一词的搜索栏。已选择“分页列表”包。

“选择项目 ”框中,单击“ 确定”。

显示“选择项目”对话框的屏幕截图。已选择“O K”按钮。

向 Index 方法添加分页功能

Controllers\StudentController.cs 中,为 PagedList 命名空间添加 using 语句:

using PagedList;

Index 方法替换为以下代码:

public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
   ViewBag.CurrentSort = sortOrder;
   ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
   ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";

   if (searchString != null)
   {
      page = 1;
   }
   else
   {
      searchString = currentFilter;
   }

   ViewBag.CurrentFilter = searchString;

   var students = from s in db.Students
                  select s;
   if (!String.IsNullOrEmpty(searchString))
   {
      students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
                             || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
   }
   switch (sortOrder)
   {
      case "name_desc":
         students = students.OrderByDescending(s => s.LastName);
         break;
      case "Date":
         students = students.OrderBy(s => s.EnrollmentDate);
         break;
      case "date_desc":
         students = students.OrderByDescending(s => s.EnrollmentDate);
         break;
      default:  // Name ascending 
         students = students.OrderBy(s => s.LastName);
         break;
   }

   int pageSize = 3;
   int pageNumber = (page ?? 1);
   return View(students.ToPagedList(pageNumber, pageSize));
}

此代码将 page 参数、当前排序顺序参数和当前筛选器参数添加到方法签名,如下所示:

public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)

第一次显示页面时,或者如果用户没有单击分页或排序链接,所有参数都将为 NULL。 如果单击分页链接,变量 page 将包含要显示的页码。

A ViewBag 属性提供具有当前排序顺序的视图,因为这必须包含在分页链接中,以便在分页时保持排序顺序相同:

ViewBag.CurrentSort = sortOrder;

另一个属性 ViewBag.CurrentFilter为视图提供当前筛选器字符串。 此值必须包含在分页链接中,以便在分页过程中保持筛选器设置,并且在页面重新显示时必须将其还原到文本框中。 如果在分页过程中搜索字符串发生变化,则页面必须重置为 1,因为新的筛选器会导致显示不同的数据。 在文本框中输入值并按下“提交”按钮时,搜索字符串将更改。 在这种情况下, searchString 参数不为 null。

if (searchString != null)
        page = 1;
else
    searchString = currentFilter;

在方法结束时, ToPagedList student IQueryable 对象上的扩展方法将学生查询转换为支持分页的集合类型中的单个学生页。 然后,将单个学生页面传递到视图:

int pageSize = 3;
int pageNumber = (page ?? 1);
return View(students.ToPagedList(pageNumber, pageSize));

ToPagedList 方法需要一个页码。 这两个问号表示 null 合并运算符。 NULL 合并运算符为可为 NULL 的类型定义默认值;表达式 (page ?? 1) 表示如果 page 有值,则返回该值,如果 page 为 NULL,则返回 1。

Views\Student\Index.cshtml 中,将现有代码替换为以下代码:

@model PagedList.IPagedList<ContosoUniversity.Models.Student>
@using PagedList.Mvc; 
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />

@{
    ViewBag.Title = "Students";
}

<h2>Students</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
    <p>
        Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)  
        <input type="submit" value="Search" />
    </p>
}
<table>
<tr>
    <th></th>
    <th>
        @Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })
    </th>
    <th>
        First Name
    </th>
    <th>
        @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
    </th>
</tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
            @Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.FirstMidName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.EnrollmentDate)
        </td>
    </tr>
}

</table>
<br />
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount

@Html.PagedListPager( Model, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter }) )

页面顶部的 @model 语句指定视图现在获取的是 PagedList 对象,而不是 List 对象。

usingPagedList.Mvc 语句提供对分页按钮的 MVC 帮助程序的访问权限。

代码使用 BeginForm 的重载,允许它指定 FormMethod.Get

@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
    <p>
        Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)  
        <input type="submit" value="Search" />
    </p>
}

默认 的 BeginForm 使用 POST 提交表单数据,这意味着参数在 HTTP 消息正文中传递,而不是作为查询字符串在 URL 中传递。 当指定 HTTP GET 时,表单数据作为查询字符串在 URL 中传递,从而使用户能够将 URL 加入书签。 有关使用 HTTP GET 的 W3C 指南指定,当操作不会导致更新时,应使用 GET。

文本框是使用当前搜索字符串初始化的,因此单击新页面时,可以看到当前搜索字符串。

Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)

列标题链接使用查询字符串向控制器传递当前搜索字符串,以便用户可以在筛选结果中进行排序:

@Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })

将显示当前页和总页数。

Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount

如果没有要显示的页面,则显示“第 0 页,共 0 页”。 (在这种情况下,页码大于页数,因为 Model.PageNumber 为 1,为 Model.PageCount 0.)

分页按钮由 PagedListPager 帮助程序显示:

@Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )

帮助 PagedListPager 程序提供了许多可以自定义的选项,包括 URL 和样式设置。 有关详细信息,请参阅 GitHub 网站上的 TroyGoode /PagedList

运行页面。

“学生索引”页的屏幕截图。

单击不同排序顺序的分页链接,以确保分页正常工作。 然后输入一个搜索字符串并再次尝试分页,以验证分页也可以正确地进行排序和筛选。

显示“学生索引”页的屏幕截图。在“按名称查找”搜索栏中输入单词 “ 。

创建显示学生统计信息的“关于”页

对于 Contoso 大学网站的“关于”页,将显示每个注册日期注册了多少名学生。 这需要对组进行分组和简单计算。 若要完成此操作,需要执行以下操作:

  • 为需要传递给视图的数据创建一个视图模型类。
  • About修改控制器中的 Home 方法。
  • About修改视图。

创建视图模型

创建 ViewModels 文件夹。 在该文件夹中,添加类文件 EnrollmentDateGroup.cs ,并将现有代码替换为以下代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.ViewModels
{
    public class EnrollmentDateGroup
    {
        [DataType(DataType.Date)]
        public DateTime? EnrollmentDate { get; set; }

        public int StudentCount { get; set; }
    }
}

修改主控制器

HomeController.cs 中,在文件顶部添加以下 using 语句:

using ContosoUniversity.DAL;
using ContosoUniversity.ViewModels;

为数据库上下文添加类变量,紧跟在类的左大括号后面:

public class HomeController : Controller
{
    private SchoolContext db = new SchoolContext();

About 方法替换为以下代码:

public ActionResult About()
{
    var data = from student in db.Students
               group student by student.EnrollmentDate into dateGroup
               select new EnrollmentDateGroup()
               {
                   EnrollmentDate = dateGroup.Key,
                   StudentCount = dateGroup.Count()
               };
    return View(data);
}

LINQ 语句按注册日期对学生实体进行分组,计算每组中实体的数量,并将结果存储在 EnrollmentDateGroup 视图模型对象的集合中。

Dispose添加方法:

protected override void Dispose(bool disposing)
{
    db.Dispose();
    base.Dispose(disposing);
}

修改“关于”视图

Views\Home\About.cshtml 文件中的代码替换为以下代码:

@model IEnumerable<ContosoUniversity.ViewModels.EnrollmentDateGroup>
           
@{
    ViewBag.Title = "Student Body Statistics";
}

<h2>Student Body Statistics</h2>

<table>
    <tr>
        <th>
            Enrollment Date
        </th>
        <th>
            Students
        </th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.EnrollmentDate)
        </td>
        <td>
            @item.StudentCount
        </td>
    </tr>
}
</table>

运行应用并单击“ 关于” 链接。 表格中会显示每个注册日期的学生计数。

About_page

可选:将应用部署到 Windows Azure

到目前为止,应用程序已在开发计算机上的 IIS Express 本地运行。 若要使其可供其他人通过 Internet 使用,必须将其部署到 Web 托管提供商。 在本教程的此可选部分中,你将将其部署到 Windows Azure 网站。

使用 Code First 迁移 部署数据库

若要部署数据库,请使用 Code First 迁移。 创建用于配置从 Visual Studio 部署的设置的发布配置文件时,将选择标记为“执行Code First 迁移 (在应用程序启动) 上运行”检查框。 此设置会导致部署过程在目标服务器上自动配置应用程序 Web.config 文件,以便 Code First 使用 MigrateDatabaseToLatestVersion 初始值设定项类。

在部署过程中,Visual Studio 不会对数据库执行任何操作。 当部署的应用程序在部署后首次访问数据库时,Code First 会自动创建数据库或将数据库架构更新到最新版本。 如果应用程序实现 Migrations Seed 方法,则该方法在创建数据库或更新架构后运行。

迁移 Seed 方法插入测试数据。 如果要部署到生产环境,则必须更改 方法, Seed 使其仅插入要插入生产数据库的数据。 例如,在当前数据模型中,你可能想要在开发数据库中设置真实课程,但要有虚构的学生。 可以编写方法 Seed 以在开发中加载两者,然后在部署到生产环境之前注释掉虚构的学生。 或者,可以编写方法 Seed 以仅加载课程,并使用应用程序的 UI 手动输入测试数据库中的虚构学生。

获取 Windows Azure 帐户

需要一个 Microsoft Azure 帐户。 如果没有帐户,只需几分钟即可创建一个免费试用帐户。 有关详细信息,请参阅 Windows Azure 免费试用版

在 Microsoft Azure 中创建网站和 SQL 数据库

您的 Microsoft Azure 网站将在共享宿主环境中运行,这意味着它将在与其他 Microsoft Azure 客户端共享的虚拟机 (VM) 上运行。 共享宿主环境是一种在云中开始工作的低成本方式。 稍后,如果你的 Web 流量增加,则应用程序可进行扩展,通过在专用 VM 上运行来满足需要。 如果您需要一个更复杂的体系结构,则可迁移到 Microsoft Azure 云服务。 云服务在你可根据自己的需求进行配置的专用 VM 上运行。

Microsoft Azure SQL 数据库是根据 SQL Server 技术构建的基于云的关系数据库服务。 与 SQL Server 配合使用的工具和应用程序也适用于SQL 数据库。

  1. Windows Azure 管理门户中,单击左侧选项卡中的“ 网站” ,然后单击“ 新建”。

    管理门户中的“新建”按钮

  2. 单击“ 自定义创建”。

    显示“新建”对话框的屏幕截图。突出显示了“网站”和“自定义创建”选项。

    此时会打开 “新建网站 - 自定义创建 ”向导。

  3. 在向导的 “新建网站” 步骤中,在 “URL ”框中输入一个字符串,用作应用程序的唯一 URL。 完整的 URL 将包含你在此处输入的内容和你在文本框旁边看到的后缀。 该图显示了“ConU”,但该 URL 可能已采用,因此必须选择其他 URL。

    管理门户中的“与数据库一起创建”链接

  4. “区域 ”下拉列表中,选择离你近的区域。 此设置指定您的网站将在哪个数据中心运行。

  5. “数据库 ”下拉列表中,选择“ 创建 20 MB 免费 SQL 数据库”。

    显示“创建网站”对话框的屏幕截图。在数据库下拉列表中,选择免费的 20 M B S Q L 数据库。突出显示了“检查标记”按钮。

  6. “数据库连接字符串名称”中,输入 SchoolContext

    显示“创建网站”对话框的屏幕截图。学校上下文在“D B 连接字符串名称”文本字段中填充。突出显示“检查标记”按钮。

  7. 单击对话框底部的向右箭头。 向导将转到 “数据库设置” 步骤。

  8. 在“ 名称 ”框中,输入 ContosoUniversityDB

  9. 在“服务器”框中,选择“新建SQL 数据库服务器”。 或者,如果之前创建了服务器,则可以从下拉列表中选择该服务器。

  10. 输入管理员 登录名密码。 如果选择了“新建 SQL 数据库服务器”,则在此处不要输入现有名称和密码。应输入新的名称和密码,现在定义的名称和密码会在以后访问数据库时使用。 如果选择了之前创建的服务器,则将输入该服务器的凭据。 在本教程中,不会选中“高级检查” 框。 使用 高级 选项可以设置数据库 排序规则

  11. 选择为网站选择的同一 区域

  12. 单击框右下角的检查标记,指示已完成。

    显示“指定数据库设置”对话框的屏幕截图,其中选择了所有设置,文本字段中包含示例密码。突出显示“检查标记”按钮。

    下图显示了使用现有 SQL Server 和登录名。

    “新建网站 - 与数据库一起创建”向导的“数据库设置”步骤

    管理门户返回到“网站”页,“ 状态” 列显示正在创建网站。 经过一段时间 (通常不到一分钟) , “状态” 列会显示网站已成功创建。 在左侧导航栏中,帐户中的站点数显示在 “网站” 图标旁边,数据库数显示在 “SQL 数据库” 图标旁边。

将应用程序部署到 Microsoft Azure

  1. 在 Visual Studio 中,在“解决方案资源管理器”中右键单击项目,并从上下文菜单中选择“发布”。

    项目上下文菜单中的“发布”

  2. “发布 Web”向导的“配置文件”选项卡中,单击“导入”。

    导入发布设置

  3. 如果您之前未在 Visual Studio 中添加 Microsoft Azure 订阅,请执行下列步骤。 在这些步骤中,将添加订阅,以便 从 Windows Azure 网站导入 下的下拉列表将包含你的网站。

    a. 在“ 导入发布配置文件 ”对话框中,单击“ 从 Windows Azure 网站导入”,然后单击“ 添加 Windows Azure 订阅”。

    添加 Microsoft Azure 订阅

    b. 在 “导入 Windows Azure 订阅 ”对话框中,单击“ 下载订阅文件”。

    下载订阅文件

    c. 在浏览器窗口中,保存 .publishsettings 文件。

    下载 .publishsettings 文件

    警告

    安全性 - publishsettings 文件包含凭据 (用于管理 Windows Azure 订阅和服务的非编码) 。 此文件的最佳安全做法是暂时将其存储在源目录之外, (例如,存储在 “库”\“文档 ”文件夹) 中,然后在导入完成后将其删除。 获取文件访问权限的 .publishsettings 恶意用户可以编辑、创建和删除 Windows Azure 服务。

    d. 在 “导入 Windows Azure 订阅 ”对话框中,单击“ 浏览 ”并导航到 .publishsettings 文件。

    下载订阅

    e. 单击“导入”。

    进口

  4. 在“ 导入发布配置文件 ”对话框中,选择“ 从 Windows Azure 网站导入”,从下拉列表中选择网站,然后单击“ 确定”。

    导入发布配置文件

  5. 在“ 连接 ”选项卡中,单击“ 验证连接 ”以确保设置正确。

    验证连接

  6. 验证连接后,“验证连接”按钮旁边会显示绿色检查标记。 单击“下一步”。

    验证成功的连接

  7. 打开“SchoolContext”下的“远程连接字符串”下拉列表,然后选择所创建数据库的连接字符串。

  8. 选择“在应用程序启动时执行Code First 迁移 (运行)

  9. 对于 UserContext (DefaultConnection) 取消选中“在运行时使用此连接字符串”,因为此应用程序未使用成员资格数据库。

    “设置”选项卡

  10. 单击“下一步”。

  11. 在“ 预览 ”选项卡中,单击“ 开始预览”。

    “预览”选项卡中的“开始预览”按钮

    该选项卡会显示将复制到服务器的文件的列表。 显示预览并不是发布应用程序所必需的,但它是一个需要了解的很有用的功能。 在本例中,你不需要对显示的文件列表执行任何操作。 下次部署此应用程序时,只有已更改的文件才会出现在此列表中。

    “开始预览”文件输出

  12. 单击“发布” 。
    Visual Studio 开始执行将文件复制到 Microsoft Azure 服务器的过程。

  13. “输出”窗口会显示已执行的部署操作并报告部署的成功完成。

    报告部署成功的输出窗口

  14. 成功完成部署后,默认浏览器会自动打开并指向已部署网站的 URL。
    创建的应用程序现在云中运行。 单击“学生”选项卡。

    Students_index_page_with_paging

此时,已在 Windows Azure SQL 数据库中创建了 SchoolContext 数据库,因为你选择了“在应用启动) 上执行Code First 迁移 (运行。 已部署网站中的 Web.config 文件已更改,以便当代码首次在数据库中读取或写入数据时, MigrateDatabaseToLatestVersion 初始值设定项将运行 (选择“ 学生 ”选项卡时) :

代码的屏幕截图,其中突出显示了“将数据库迁移到最新版本”。

部署过程还创建了一个新的连接字符串 (SchoolContext_DatabasePublish) ,供Code First 迁移用于更新数据库架构和设定数据库种子。

Database_Publish连接字符串

DefaultConnection 连接字符串适用于在本教程) 未使用的成员资格数据库 (。 SchoolContext 连接字符串适用于 ContosoUniversity 数据库。

可以在自己的计算机上找到 Web.config 文件的已部署版本 ,ContosoUniversity\obj\Release\Package\PackageTmp\Web.config。可以使用 FTP 访问部署 的Web.config 文件本身。 有关说明,请参阅 使用 Visual Studio ASP.NET Web 部署:部署代码更新。 按照以“若要使用 FTP 工具,需要三项内容:FTP URL、用户名和密码”开头的说明。

注意

Web 应用不实现安全性,因此找到 URL 的任何人都可以更改数据。 有关如何保护网站的说明,请参阅将具有成员资格、OAuth 和SQL 数据库的安全 ASP.NET MVC 应用部署到 Windows Azure 网站。 可以通过在 Visual Studio 中使用 Windows Azure 管理门户或 服务器资源管理器 来阻止其他人使用该站点。

服务器资源管理器的屏幕截图,其中显示了已展开的“Windows Azure 网站”选项卡,并在其下方选择了“Con U”。突出显示了“停止网站”选项的对话框菜单。

Code First 初始值设定项

在部署部分中,你看到了正在使用 MigrateDatabaseToLatestVersion 初始值设定项。 Code First 还提供可以使用的其他初始值设定项,包括 CreateDatabaseIfNotExists (默认) DropCreateDatabaseIfModelChangesDropCreateDatabaseAlways。 初始 DropCreateAlways 值设定项可用于设置单元测试的条件。 还可以编写自己的初始值设定项,如果不想等到应用程序读取或写入数据库,则可以显式调用初始值设定项。 有关初始值设定项的完整说明,请参阅 Julie Lerman 和 Rowan Miller 的 编程实体框架:Code First 一书的第 6 章。

总结

本教程介绍了如何创建数据模型并实现基本的 CRUD、排序、筛选、分页和分组功能。 在下一教程中,你将通过扩展数据模型开始了解更高级的主题。

可以在 ASP.NET 数据访问内容映射中找到指向其他实体框架资源的链接。