使用模型绑定和 Web 窗体检索和显示数据

本教程系列演示了将模型绑定与 ASP.NET Web Forms项目配合使用的基本方面。 模型绑定使数据交互比处理数据源对象(如 ObjectDataSource 或 SqlDataSource) ) (更直接。 本系列从介绍性材料开始,在后面的教程中将介绍更高级的概念。

模型绑定模式适用于任何数据访问技术。 在本教程中,你将使用 Entity Framework,但你可以使用你最熟悉的数据访问技术。 在数据绑定服务器控件(如 GridView、ListView、DetailsView 或 FormView 控件)中,指定要用于选择、更新、删除和创建数据的方法的名称。 在本教程中,你将为 SelectMethod 指定一个值。

在该方法中,提供用于检索数据的逻辑。 在下一教程中,你将为 UpdateMethod、DeleteMethod 和 InsertMethod 设置值。

可以使用 C# 或 Visual Basic 下载 完整的项目。 可下载的代码适用于 Visual Studio 2012 及更高版本。 它使用 Visual Studio 2012 模板,该模板与本教程中显示的 Visual Studio 2017 模板略有不同。

本教程在 Visual Studio 中运行应用程序。 还可以将应用程序部署到托管提供商,并通过 Internet 提供该应用程序。 Microsoft 在 中为最多 10 个网站提供免费 Web 托管
免费 Azure 试用帐户。 有关如何将 Visual Studio Web 项目部署到Azure 应用服务 Web 应用的信息,请参阅使用 Visual Studio ASP.NET Web 部署系列。 本教程还演示如何使用 Entity Framework Code First 迁移 将 SQL Server 数据库部署到 Azure SQL 数据库。

本教程中使用的软件版本

  • Microsoft Visual Studio 2017 或 Microsoft Visual Studio Community 2017

本教程还适用于 Visual Studio 2012 和 Visual Studio 2013,但在用户界面和项目模板方面存在一些差异。

生成目标

在本教程中,你将:

  • 生成反映学生已注册课程的大学的数据对象
  • 从对象生成数据库表
  • 使用测试数据填充数据库
  • 在 Web 窗体中显示数据

创建项目

  1. 在 Visual Studio 2017 中,创建名为 ContosoUniversityModelBinding的 ASP.NET Web 应用程序 (.NET Framework) 项目。

    创建项目

  2. 选择“确定” 。 此时将显示用于选择模板的对话框。

    选择 Web 窗体

  3. 选择Web Forms模板。

  4. 如有必要,请将身份验证更改为 “个人用户帐户”。

  5. 选择“确定”以创建项目。

修改网站外观

进行一些更改以自定义网站外观。

  1. 打开 Site.Master 文件。

  2. 更改标题以显示 Contoso University ,而不是 “我的 ASP.NET 应用程序”。

    <title><%: Page.Title %> - Contoso University</title>
    
  3. 将标题文本从 “应用程序名称” 更改为 “Contoso University”。

    <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" runat="server" href="~/">Contoso University</a>
    </div>
    
  4. 将导航标头链接更改为网站相应的链接。

    删除“ 关于 ”和 “联系人” 的链接,并改为链接到要创建的 “学生 ”页面。

    <ul class="nav navbar-nav">
        <li><a runat="server" href="~/">Home</a></li>
        <li><a runat="server" href="~/Students">Students</a></li>
    </ul>
    
  5. 保存 Site.Master。

添加 Web 窗体以显示学生数据

  1. “解决方案资源管理器”中,右键单击项目,选择“添加”,然后选择“新建项”。

  2. 在“ 添加新项 ”对话框中,选择 包含母版页模板的 Web 窗体 ,并将其命名为 Students.aspx

    创建页面

  3. 选择 添加

  4. 对于 Web 窗体的母版页,选择“ Site.Master”。

  5. 选择“确定” 。

添加数据模型

Models 文件夹中,添加名为 UniversityModels.cs 的类。

  1. 右键单击“ 模型”,选择“ 添加”,然后选择“ 新建项”。 此时会显示“添加新项”对话框。

  2. 在左侧导航菜单中,依次选择“ 代码”、“ ”。

    create model 类

  3. 将课堂命名为 UniversityModels.cs ,然后选择“ 添加”。

    在此文件中,定义 SchoolContextStudentEnrollmentCourse 类,如下所示:

    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.ComponentModel.DataAnnotations;
    
    namespace ContosoUniversityModelBinding.Models
    {
        public class SchoolContext : DbContext
        {
            public DbSet<Student> Students { get; set; }
            public DbSet<Enrollment> Enrollments { get; set; }
            public DbSet<Course> Courses { get; set; }
        }
    
        public class Student
        {
            [Key, Display(Name = "ID")]
            [ScaffoldColumn(false)]
            public int StudentID { get; set; }
    
            [Required, StringLength(40), Display(Name="Last Name")]
            public string LastName { get; set; }
    
            [Required, StringLength(20), Display(Name = "First Name")]
            public string FirstName { get; set; }
    
            [EnumDataType(typeof(AcademicYear)), Display(Name = "Academic Year")]
            public AcademicYear Year { get; set; }
    
            public virtual ICollection<Enrollment> Enrollments { get; set; }
        }
    
        public class Enrollment
        {
            [Key]
            public int EnrollmentID { get; set; }
            public int CourseID { get; set; }
            public int StudentID { get; set; }
            public decimal? Grade { get; set; }
            public virtual Course Course { get; set; }
            public virtual Student Student { get; set; }
        }
    
        public class Course
        {
            [Key]
            public int CourseID { get; set; }
            public string Title { get; set; }
            public int Credits { get; set; }
            public virtual ICollection<Enrollment> Enrollments { get; set; }
        } 
    
        public enum AcademicYear
        {
            Freshman,
            Sophomore,
            Junior,
            Senior
        }
    }
    

    SchoolContext 派生自 DbContext,后者管理数据库连接和数据更改。

    Student在 类中,请注意应用于 、 LastNameYear 属性的属性FirstName。 本教程使用这些属性进行数据验证。 为了简化代码,只有这些属性使用数据验证属性进行标记。 在实际项目中,需要验证的所有属性都应用验证属性。

  4. 保存 UniversityModels.cs。

基于类设置数据库

本教程使用 Code First 迁移 创建对象和数据库表。 这些表存储有关学生及其课程的信息。

  1. 选择“工具”>“NuGet 包管理器”>“包管理器控制台”。

  2. 包管理器控制台中,运行以下命令:
    enable-migrations -ContextTypeName ContosoUniversityModelBinding.Models.SchoolContext

    如果命令成功完成,将显示一条消息,指出已启用迁移。

    启用迁移

    请注意,已创建名为 Configuration.cs 的文件。 类 Configuration 具有一个 Seed 方法,该方法可以使用测试数据预填充数据库表。

预填充数据库

  1. 打开 Configuration.cs。

  2. 将以下代码添加到 Seed 方法中。 此外,为 ContosoUniversityModelBinding. Models 命名空间添加 using 语句。

    namespace ContosoUniversityModelBinding.Migrations
    {
        using System;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
        using ContosoUniversityModelBinding.Models;
    
        internal sealed class Configuration : DbMigrationsConfiguration<SchoolContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(SchoolContext context)
            {
    
                context.Students.AddOrUpdate(
                     new Student { 
                         FirstName = "Carson", 
                         LastName = "Alexander", 
                         Year = AcademicYear.Freshman },
                     new Student { 
                         FirstName = "Meredith", 
                         LastName = "Alonso", 
                         Year = AcademicYear.Freshman },
                     new Student { 
                         FirstName = "Arturo", 
                         LastName = "Anand", 
                         Year = AcademicYear.Sophomore },
                     new Student { 
                         FirstName = "Gytis", 
                         LastName = "Barzdukas", 
                         Year = AcademicYear.Sophomore },
                     new Student { 
                         FirstName = "Yan", 
                         LastName = "Li", 
                         Year = AcademicYear.Junior },
                     new Student { 
                         FirstName = "Peggy", 
                         LastName = "Justice", 
                         Year = AcademicYear.Junior },
                     new Student { 
                         FirstName = "Laura", 
                         LastName = "Norman", 
                         Year = AcademicYear.Senior },
                     new Student { 
                         FirstName = "Nino", 
                         LastName = "Olivetto", 
                         Year = AcademicYear.Senior }
                     );
    
                context.SaveChanges();
    
                context.Courses.AddOrUpdate(
                    new Course { Title = "Chemistry", Credits = 3 },
                    new Course { Title = "Microeconomics", Credits = 3 },
                    new Course { Title = "Macroeconomics", Credits = 3 },
                    new Course { Title = "Calculus", Credits = 4 },
                    new Course { Title = "Trigonometry", Credits = 4 },
                    new Course { Title = "Composition", Credits = 3 },
                    new Course { Title = "Literature", Credits = 4 }
                    );
    
                context.SaveChanges();
    
                context.Enrollments.AddOrUpdate(
                    new Enrollment { StudentID = 1, CourseID = 1, Grade = 1 },
                    new Enrollment { StudentID = 1, CourseID = 2, Grade = 3 },
                    new Enrollment { StudentID = 1, CourseID = 3, Grade = 1 },
                    new Enrollment { StudentID = 2, CourseID = 4, Grade = 2 },
                    new Enrollment { StudentID = 2, CourseID = 5, Grade = 4 },
                    new Enrollment { StudentID = 2, CourseID = 6, Grade = 4 },
                    new Enrollment { StudentID = 3, CourseID = 1 },
                    new Enrollment { StudentID = 4, CourseID = 1 },
                    new Enrollment { StudentID = 4, CourseID = 2, Grade = 4 },
                    new Enrollment { StudentID = 5, CourseID = 3, Grade = 3 },
                    new Enrollment { StudentID = 6, CourseID = 4 },
                    new Enrollment { StudentID = 7, CourseID = 5, Grade = 2 }
                    );
    
                context.SaveChanges();
            }
        }
    }
    
  3. 保存 Configuration.cs。

  4. 在包管理器控制台中,运行 命令 add-migration initial

  5. 运行 命令 update-database

    如果在运行此命令时收到异常, StudentID 则 和 CourseID 值可能与方法值不同 Seed 。 打开这些数据库表,查找 和 CourseID的现有值StudentID。 将这些值添加到代码中,以便对表进行种子设定 Enrollments

添加 GridView 控件

使用填充的数据库数据,现在可以检索并显示该数据。

  1. 打开 Students.aspx。

  2. MainContent找到占位符。 在该占位符中,添加包含此代码的 GridView 控件。

    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <asp:GridView runat="server" ID="studentsGrid"
            ItemType="ContosoUniversityModelBinding.Models.Student" DataKeyNames="StudentID" 
            SelectMethod="studentsGrid_GetData"
            AutoGenerateColumns="false">
            <Columns>
                <asp:DynamicField DataField="StudentID" />
                <asp:DynamicField DataField="LastName" />
                <asp:DynamicField DataField="FirstName" />
                <asp:DynamicField DataField="Year" />          
                <asp:TemplateField HeaderText="Total Credits">
                  <ItemTemplate>
                    <asp:Label Text="<%# Item.Enrollments.Sum(en => en.Course.Credits) %>" 
                        runat="server" />
                  </ItemTemplate>
                </asp:TemplateField>        
            </Columns>
        </asp:GridView>
    </asp:Content>
    

    注意事项:

    • 请注意 GridView 元素中为 SelectMethod 属性设置的值。 此值指定用于检索在下一步中创建的 GridView 数据的方法。

    • 属性 ItemType 设置为 Student 前面创建的类。 此设置允许引用标记中的类属性。 例如, Student 类具有名为 的 Enrollments集合。 可以使用 Item.Enrollments 检索该集合,然后使用 LINQ 语法 检索每个学生的注册学分总和。

  3. 保存 Students.aspx。

添加代码以检索数据

在 Students.aspx 代码隐藏文件中,添加为 SelectMethod 值指定的 方法。

  1. 打开 Students.aspx.cs。

  2. ContosoUniversityModelBinding. ModelsSystem.Data.Entity 命名空间添加using语句。

    using ContosoUniversityModelBinding.Models;
    using System.Data.Entity;
    
  3. 添加为 SelectMethod指定的方法:

    public IQueryable<Student> studentsGrid_GetData()
    {
        SchoolContext db = new SchoolContext();
        var query = db.Students.Include(s => s.Enrollments.Select(e => e.Course));
        return query;
    }
    

    Include 句可提高查询性能,但不是必需的。 Include如果没有 子句,则使用延迟加载检索数据,这涉及到每次检索相关数据时都会向数据库发送单独的查询。 Include使用 子句,使用预先加载检索数据,这意味着单个数据库查询检索所有相关数据。 如果未使用相关数据,则预先加载效率较低,因为检索的数据更多。 但是,在这种情况下,预先加载可提供最佳性能,因为每个记录都显示相关数据。

    有关加载相关数据时的性能注意事项的详细信息,请参阅 ASP.NET MVC 应用程序中使用实体框架读取相关数据一文中的延迟、预先和显式加载相关数据部分。

    默认情况下,数据按标记为键的属性的值进行排序。 可以添加 子 OrderBy 句以指定不同的排序值。 在此示例中,默认 StudentID 属性用于排序。 在 排序、分页和筛选数据 一文中,用户可选择要排序的列。

  4. 保存 Students.aspx.cs。

运行应用程序

(F5) 运行 Web 应用程序,然后导航到“ 学生 ”页,其中显示以下内容:

显示数据

自动生成模型绑定方法

完成本教程系列时,只需将教程中的代码复制到项目中即可。 但是,此方法的一个缺点是,你可能不知道 Visual Studio 提供的用于自动生成模型绑定方法代码的功能。 在处理自己的项目时,自动生成代码可以节省时间,并帮助你了解如何实现操作。 本部分介绍自动生成代码功能。 本部分仅提供信息,不包含需要在项目中实现的任何代码。

在标记代码中 SelectMethod为 、 UpdateMethodInsertMethodDeleteMethod 属性设置值时,可以选择 “创建新方法” 选项。

创建方法

Visual Studio 不仅在代码隐藏中创建具有适当签名的方法,而且还生成实现代码来执行操作。 如果在使用自动生成代码功能之前首先设置 ItemType 属性,则生成的代码将使用该类型执行操作。 例如,设置 UpdateMethod 属性时,会自动生成以下代码:

// The id parameter name should match the DataKeyNames value set on the control
public void studentsGrid_UpdateItem(int id)
{
    ContosoUniversityModelBinding.Models.Student item = null;
    // Load the item here, e.g. item = MyDataLayer.Find(id);
    if (item == null)
    {
        // The item wasn't found
        ModelState.AddModelError("", String.Format("Item with id {0} was not found", id));
        return;
    }
    TryUpdateModel(item);
    if (ModelState.IsValid)
    {
        // Save changes here, e.g. MyDataLayer.SaveChanges();

    }
}

同样,无需将此代码添加到项目中。 在下一教程中,你将实现更新、删除和添加新数据的方法。

总结

在本教程中,你创建了数据模型类,并从这些类生成了一个数据库。 用测试数据填充了数据库表。 你使用模型绑定从数据库中检索数据,然后在 GridView 中显示数据。

在本系列的下一 个教程 中,你将启用更新、删除和创建数据。