使用模型系結和 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 中執行應用程式。 您也可以將應用程式部署至主機提供者,並透過網際網路提供它。 Microsoft 在 中提供最多 10 個網站的免費 Web 裝載
免費的 Azure 試用版帳戶。 如需如何將 Visual Studio Web 專案部署至Azure App 服務 Web Apps的詳細資訊,請參閱使用 Visual Studio ASP.NET Web 部署系列。 該教學課程也會示範如何使用 Entity Framework Code First 移轉 將SQL Server資料庫部署至 Azure SQL Database。

教學課程中使用的軟體版本

  • Microsoft Visual Studio 2017 或 Microsoft Visual Studio Community 2017

本教學課程也適用于 Visual Studio 2012 和 Visual Studio 2013,但使用者介面和專案範本有一些差異。

您將建置什麼

在本教學課程中,您將會:

  • 建置資料物件,以反映學生已註冊課程的大學
  • 從 物件建置資料庫資料表
  • 以測試資料填入資料庫
  • 以 Web 表單顯示資料

建立專案

  1. 在 Visual Studio 2017 中,建立名為ContosoUniversityModelBindingASP.NET Web 應用程式 (.NET Framework) 專案。

    建立專案

  2. 選取 [確定]。 選取範本的對話方塊隨即出現。

    選取 Web 表單

  3. 選取Web Form範本。

  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. 將流覽標頭連結變更為網站適當的連結。

    請移除 [關於 ] 和 [ 連絡人 ] 的連結,並改為連結到您將建立的 Students 頁面。

    <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. 從左側導覽功能表中,選取 [ 程式碼],然後選取 [ 類別]。

    建立模型類別

  3. 將類別命名為 UniversityModels.cs ,然後選取 [ 新增]。

    在此檔案中 SchoolContext ,定義 、 StudentEnrollmentCourse 類別,如下所示:

    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 ,請注意套用至 FirstNameLastNameYear 屬性的屬性。 本教學課程會使用這些屬性進行資料驗證。 為了簡化程式碼,只有這些屬性會標示資料驗證屬性。 在實際專案中,您會將驗證屬性套用至所有需要驗證的屬性。

  4. 儲存 UniversityModels.cs。

根據類別設定資料庫

本教學課程使用Code First 移轉來建立物件和資料庫資料表。 這些表格會儲存學生及其課程的相關資訊。

  1. 選取 [工具]>[NuGet 套件管理員]>[套件管理員主控台]。

  2. 套件管理員主控台中,執行此命令:
    enable-migrations -ContextTypeName ContosoUniversityModelBinding.Models.SchoolContext

    如果命令順利完成,則會出現一則訊息,指出已啟用移轉。

    啟用移轉

    請注意,已建立名為 Configuration.cs 的檔案。 類別 Configuration 具有 Seed 方法,其可使用測試資料預先填入資料庫資料表。

預先填入資料庫

  1. 開啟 Configuration.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. 儲存 Configuration.cs。

  4. 在套件管理員主控台中,執行命令 add-migration initial

  5. 執行命令 update-database

    如果您在執行此命令時收到例外狀況, StudentIDCourseID 值可能會與 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. 新增 usingSystem.Data.Entity 命名空間的 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使用 子句時,會使用積極式載入來擷取資料,這表示單一資料庫查詢會擷取所有相關資料。 如果未使用相關資料,則積極式載入效率較低,因為會擷取更多資料。 不過,在此情況下,積極式載入可讓您獲得最佳效能,因為每個記錄都會顯示相關的資料。

    For more information about performance considerations when loading related data, see the Lazy, Eager, and Explicit Loading of Related Data section in the Reading Related Data with the Entity Framework in an ASP.NET MVC Application article.

    根據預設,資料會依標示為索引鍵的 屬性值來排序。 您可以新增 OrderBy 子句來指定不同的排序值。 在此範例中,預設 StudentID 屬性用於排序。 在 [排序]、[分頁] 和 [篩選資料 ] 一文中,使用者已啟用來選取要排序的資料行。

  4. 儲存 Students.aspx.cs。

執行您的應用程式

執行 Web 應用程式 (F5) 並流覽至 Students 頁面,其中會顯示下列內容:

顯示資料

自動產生模型系結方法

完成本教學課程系列時,您只要將程式碼從教學課程複製到您的專案即可。 不過,此方法的其中一個缺點是,您可能不知道 Visual Studio 所提供的功能,以自動產生模型系結方法的程式碼。 當您處理自己的專案時,自動產生程式碼可以節省您的時間,並協助您瞭解如何實作作業。 本節說明自動產生程式碼的功能。 本節僅供參考,不包含您在專案中實作的任何程式碼。

在標記程式碼中設定 、 UpdateMethodInsertMethodDeleteMethod 屬性的值 SelectMethod 時,您可以選取 [建立新方法] 選項。

建立方法

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 中顯示資料。

在本系列中的下一個 教學課程中 ,您將啟用更新、刪除和建立資料。