使用模型绑定和 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 窗体 并将其命名为 学生.aspx

    创建页面

  3. 选择 添加

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

  5. 选择“确定”。

添加数据模型

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

  1. 右键单击 “模型”,选择“ 添加”,然后选择 “新建项”。 “添加新项” 对话框随即出现。

  2. 在左侧导航菜单中,选择“ 代码”,然后选择 “类”。

    创建模型类

  3. Class 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 ,请注意应用于 FirstName属性 LastNameYear 属性的属性。 本教程使用这些属性进行数据验证。 为了简化代码,只有这些属性使用数据验证属性进行标记。 在实际项目中,将验证属性应用于需要验证的所有属性。

  4. 保存 UniversityModels.cs。

基于类设置数据库

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

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

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

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

    启用迁移

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

预填充数据库

  1. 打开配置.cs。

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

    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. 保存配置.cs。

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

  5. 运行命令 update-database

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

添加 GridView 控件

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

  1. 打开学生.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. 保存学生.aspx。

添加代码以检索数据

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

  1. 打开学生.aspx.cs。

  2. 为命名空间System.Data.Entity添加using语句ContosoUniversityModelBinding. Models

    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. 保存学生.aspx.cs。

运行应用程序

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

显示数据

自动生成模型绑定方法

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

在标记代码中设置值SelectMethodDeleteMethodUpdateMethodInsertMethod或属性时,可以选择“新建方法”选项。

创建方法

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 中显示数据。

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