共用方式為


為 ASP.NET MVC 應用程式建立 Entity Framework 資料模型(1/10)

Tom Dykstra

Contoso University 範例 Web 應用程式示範如何使用 Entity Framework 5 和 Visual Studio 2012 建立 ASP.NET MVC 4 應用程式。 這個範例應用程式是虛構的 Contoso 大學網站。 其中包括的功能有學生入學許可、課程建立、教師指派。 本教學課程系列說明如何建置 Contoso University 範例應用程式。

Code First

在 Entity Framework 中使用數據的方式有三種:Database FirstModel First 和 Code First。 本教學課程適用於 Code First。 如需這些工作流程之間的差異,以及如何為您的案例選擇最佳工作流程的指引,請參閱 Entity Framework 開發工作流程

MVC

範例應用程式建置在 ASP.NET MVC。 如果您想要使用 ASP.NET Web Form模型,請參閱模型系結和 Web Form 教學課程系列和 ASP.NET 數據存取內容對應

軟體版本

教學課程中所示 也可搭配使用
Windows 8 Windows 7
Visual Studio 2012 Visual Studio 2012 Express for Web。 如果您還沒有 VS 2012 或 VS 2012 Express for Web,則 Windows Azure SDK 會自動安裝此專案。 Visual Studio 2013 應該可以運作,但本教學課程尚未經過測試,而且某些功能表選取專案和對話框不同。 Windows Azure 部署需要 VS 2013 版本的 Windows Azure SDK
.NET 4.5 顯示的大部分功能都會在 .NET 4 中運作,但有些功能將無法運作。 例如,EF 中的列舉支援需要 .NET 4.5。
Entity Framework 5
Windows Azure SDK 2.1 如果您略過 Windows Azure 部署步驟,就不需要 SDK。 發行新版本的 SDK 時,鏈接會安裝較新版本。 在此情況下,您可能必須調整一些指示來適應新的UI和功能。

問題

如果您有與教學課程沒有直接相關的問題,您可以將問題張貼至 ASP.NET entity Framework 論壇、Entity Framework 和 LINQ to Entities 論壇,或 StackOverflow.com

通知

請參閱系列中的最後一個教學課程以瞭解 通知和 VB 的相關注意事項。

Contoso University Web 應用程式

您在這些教學課程中會建置的應用程式為一個簡單的大學網站。

使用者可以檢視和更新學生、課程和教師資訊。 以下是您會建立的幾個畫面。

Students_Index_page

顯示範例 Contoso University Web 應用程式的 Students 搜尋頁面和 [建立新學生] 頁面的螢幕快照。

此網站的 UI 樣式與內建範本產生的相當類似,以使此教學課程能聚焦於如何使用 Entity Framework。

必要條件

本教學課程中的指示和螢幕快照假設您使用Visual Studio 2012或Visual Studio 2012 Express for Web,且自 2013 年 7 月起安裝最新更新和適用於 .NET 的 Azure SDK。 您可以使用下列連結來取得這一切:

適用於 .NET 的 Azure SDK (Visual Studio 2012)

如果您已安裝 Visual Studio,上述連結將會安裝任何遺失的元件。 如果您沒有 Visual Studio,連結將會安裝 Visual Studio 2012 Express for Web。 您可以使用 Visual Studio 2013,但某些必要的程式和畫面會有所不同。

建立MVC Web 應用程式

開啟 Visual Studio,並使用 ASP.NET MVC 4 Web 應用程式 範本建立名為 “ContosoUniversity” 的新 C# 專案。 請確定以 .NET Framework 4.5 為目標(您將使用 enum 屬性,且需要 .NET 4.5)。

New_project_dialog_box

在 [ 新增 ASP.NET MVC 4 專案 ] 對話框中,選取 [因特網應用程式 ] 範本。

保留選取 [ Razor 檢視引擎],然後清除 [ 建立單元測試專案 ] 複選框。

按一下 [確定]

Project_template_options

設定網站樣式

一些簡單的變更會設定網站的功能表、配置和首頁。

開啟 Views\Shared\_Layout.cshtml,並以下列程式代碼取代檔案的內容。 所做的變更已醒目提示。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - Contoso University</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")
    </head>
    <body>
        <header>
            <div class="content-wrapper">
                <div class="float-left">
                    <p class="site-title">@Html.ActionLink("Contoso University", "Index", "Home")</p>
                </div>
                <div class="float-right">
                    <section id="login">
                        @Html.Partial("_LoginPartial")
                    </section>
                    <nav>
                        <ul id="menu">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("About", "About", "Home")</li>
                            <li>@Html.ActionLink("Students", "Index", "Student")</li>
                            <li>@Html.ActionLink("Courses", "Index", "Course")</li>
                            <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li>
                            <li>@Html.ActionLink("Departments", "Index", "Department")</li>
                        </ul>
                    </nav>
                </div>
            </div>
        </header>
        <div id="body">
            @RenderSection("featured", required: false)
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>
        <footer>
            <div class="content-wrapper">
                <div class="float-left">
                    <p>&copy; @DateTime.Now.Year - Contoso University</p>
                </div>
            </div>
        </footer>

        @Scripts.Render("~/bundles/jquery")
        @RenderSection("scripts", required: false)
    </body>
</html>

此程式碼會進行下列變更:

  • 以 「Contoso University」 取代 「My ASP.NET MVC Application」 和 “your logo here” 的範本實例。
  • 新增數個稍後將在教學課程中使用的動作連結。

Views\Home\Index.cshtml 中,將檔案的內容取代為下列程式代碼,以排除有關 ASP.NET 和 MVC 的範本段落:

@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>
        </div>
    </section>
}

Controllers\HomeController.csIndex,將 Action 方法中的 值ViewBag.Message變更為 “Welcome to Contoso University!”,如下列範例所示:

public ActionResult Index()
{
    ViewBag.Message = "Welcome to Contoso University";

    return View();
}

按 CTRL+F5 以執行網站。 您會看到主功能表的首頁。

Contoso_University_home_page

建立數據模型

接下來您會為 Contoso 大學應用程式建立實體類別。 您將從下列三個實體開始:

Class_diagram

StudentEnrollment 實體之間存在一對多關聯性,CourseEnrollment 實體之間也存在一對多關聯性。 換句話說,一位學生可以註冊並參加任何數目的課程,而一個課程也可以有任何數目的學生註冊。

在下節中,您會為這些實體建立各自的類別。

注意

如果您在完成建立所有這些實體類別之前嘗試編譯專案,您將會收到編譯程序錯誤。

學生實體

Student_entity

在 Models 資料夾中,建立 Student.cs,並以下列程式代碼取代現有的程式代碼:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int StudentID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

StudentID 屬性會成為資料庫資料表中的主索引鍵資料行,並對應至這個類別。 根據預設,Entity Framework 會將名為 IDclassname ID 的屬性解譯為主鍵。

Enrollments 屬性為導覽屬性。 導覽屬性會保留與此實體相關的其他實體。 在此情況下,Enrollments實體的 Student 屬性會保存與該Student實體相關的所有Enrollment實體。 換句話說,如果資料庫中的指定 Student 數據列有兩個相關 Enrollment 數據列(在其外鍵數據行中包含 StudentID 該學生主鍵值的數據列),該 Student 實體的 Enrollments 導覽屬性將會包含這兩 Enrollment 個實體。

瀏覽屬性通常會定義為 virtual ,以便利用某些 Entity Framework 功能,例如 延遲載入。 (稍後會在 中 說明延遲載入閱讀本系列稍後的相關數據 教學課程。

若導覽屬性可保有多個實體 (例如在多對多或一對多關聯性中的情況),其類型必須為一個清單,使得實體可以在該清單中新增、刪除或更新,例如 ICollection

註冊實體

Enrollment_entity

Models 資料夾中,建立 Enrollment.cs,然後使用下列程式碼取代現有的程式碼:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }
        
        public virtual Course Course { get; set; }
        public virtual Student Student { get; set; }
    }
}

Grade 屬性是 列舉Grade 型別宣告後方的問號表示 Grade 屬性可為 Null。 Null 的等級與零等級不同, Null 表示尚未知道或尚未指派等級。

StudentID 屬性是外部索引鍵,對應的導覽屬性是 StudentEnrollment 實體與一個 Student 實體關聯,因此屬性僅能保有單一 Student 實體 (不像您先前看到的 Student.Enrollments 導覽屬性可保有多個 Enrollment 實體)。

CourseID 屬性是外部索引鍵,對應的導覽屬性是 Course。 一個 Enrollment 實體與一個 Course 實體建立關聯。

Course 實體

Course_entity

在 Models 資料夾中,建立 Course.cs,以下列程式代碼取代現有的程式代碼:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

Enrollments 屬性為導覽屬性。 Course 實體可以與任何數量的 Enrollment 實體相關。

我們將進一步說明 [DatabaseGenerated(DatabaseGeneratedOption]。下一個教學課程中的 None)] 屬性。 基本上,此屬性可讓您為課程輸入主索引鍵,而非讓資料庫產生它。

建立資料庫內容

協調指定數據模型的 Entity Framework 功能的主要類別是 資料庫內容 類別。 您可以從 System.Data.Entity.DbContext 類別衍生來建立這個類別。 在您的程式碼中,您會指定資料模型中包含哪些實體。 您也可以自訂某些 Entity Framework 行為。 在此專案中,類別命名為 SchoolContext

建立名為 DAL 的資料夾(適用於資料存取層)。 在該資料夾中,建立名為 SchoolContext.cs 的新類別檔案,並以下列程式代碼取代現有的程式代碼:

using ContosoUniversity.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ContosoUniversity.DAL
{
    public class SchoolContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }
}

此程式代碼會 為每個實體集建立 DbSet 屬性。 在 Entity Framework 術語中, 實體集 通常會對應至資料庫數據表,而 實體 則對應至數據表中的數據列。

modelBuilder.Conventions.Remove OnModelCreating 方法中的語句可防止數據表名稱進行複數化。 如果您未這麼做,產生的數據表會命名為 StudentsCoursesEnrollments。 相反地,資料表名稱會是 StudentCourseEnrollment。 針對是否要複數化資料表名稱,開發人員並沒有共識。 本教學課程使用單一窗體,但重要的是,您可以藉由包含或省略這一行程式代碼來選取您偏好的窗體。

SQL Server Express LocalDB

LocalDB 是輕量型版本的 SQL Server Express 資料庫引擎,會視需要啟動,並在使用者模式中執行。 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 預設會隨 Visual Studio 一起安裝;如果您使用 Visual Studio 2010,則必須手動安裝它。

在本教學課程中,您將使用LocalDB,讓資料庫可以儲存在 App_Data資料夾中做為.mdf檔案。 開啟根 Web.config 檔案,並將新的 連接字串 新增至connectionStrings集合,如下列範例所示。 (請務必更新 根項目資料夾中的 Web.config 檔案。另外 還有 Web.config 檔案位於您不需要更新的 Views 子資料夾中。

<add name="SchoolContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\ContosoUniversity.mdf" providerName="System.Data.SqlClient" />

根據預設,Entity Framework 會尋找名為 與 類別相同DbContext之 連接字串(SchoolContext針對此專案)。 您新增的 連接字串 會指定名為 ContosoUniversity.mdf 的 LocalDB 資料庫,該資料庫位於 App_Data 資料夾中。 如需詳細資訊,請參閱 ASP.NET Web 應用程式的 SQL Server 連接字串。

您實際上不需要指定 連接字串。 如果您沒有提供 連接字串,Entity Framework 會為您建立一個;不過,資料庫可能不在應用程式的 App_data 資料夾中。 如需將建立資料庫之位置的資訊,請參閱 Code First to a New Database

集合connectionStrings也有名為 DefaultConnection 的 連接字串,用於成員資格資料庫。 在本教學課程中,您不會使用成員資格資料庫。 兩個 連接字串 之間的唯一差異是資料庫名稱和名稱屬性值。

設定和執行程式代碼第一次移轉

當您第一次開始開發應用程式時,數據模型會經常變更,而且每次模型變更時,都會與資料庫同步。 您可以設定 Entity Framework,以在每次變更數據模型時自動卸除和重新建立資料庫。 這不是開發初期的問題,因為測試數據很容易重新建立,但在部署至生產環境之後,您通常會想要更新資料庫架構而不卸除資料庫。 移轉功能可讓 Code First 更新資料庫,而不需卸除並重新建立資料庫。 在新的項目開發週期早期,您可能想要使用 DropCreateDatabaseIfModelChanges 來卸除、重新建立和重新植入資料庫,每次模型變更時。 一個您已準備好部署應用程式,您可以轉換成移轉方法。 在本教學課程中,您只會使用移轉。 如需詳細資訊,請參閱 Code First 移轉移轉螢幕廣播系列

啟用 Code First 移轉

  1. 從 [工具] 功能表中,按兩下 [NuGet 封裝管理員],然後 封裝管理員 控制台

    Selecting_Package_Manager_Console

  2. PM> 提示字元中輸入下列命令:

    enable-migrations -contexttypename SchoolContext
    

    enable-migrations 命令

    此命令會在 ContosoUniversity 專案中建立 Migrations 資料夾,並將該資料夾 放入您可以編輯以設定 Migrations 的Configuration.cs 檔案。

    Migrations 資料夾

    類別 Configuration 包含方法 Seed ,這個方法會在建立資料庫時呼叫,而且每次在數據模型變更後更新它時都會呼叫。

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.Models.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.Models.SchoolContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
    

    此方法 Seed 的目的是要讓您在 Code First 建立測試數據或更新測試數據之後,將測試數據插入資料庫中。

設定 Seed 方法

Seed 方法會在 Code First 移轉 建立資料庫時執行,每次更新資料庫到最新的移轉時。 Seed 方法的目的是讓您能夠在應用程式第一次存取資料庫之前,將數據插入數據表中。

在舊版的Code First中,在移轉發行之前,插入測試數據的方法很常見 Seed ,因為在開發期間,資料庫的每個模型變更都必須從頭完全刪除並重新建立。 使用 Code First 移轉 時,測試數據會在資料庫變更之後保留,因此通常不需要在 Seed 方法中包含測試數據。 事實上,如果您要使用移轉將資料庫部署至生產環境,則不希望 Seed 方法插入測試數據,因為 Seed 方法將在生產環境中執行。 在此情況下,您希望 Seed 方法只將您想要插入生產環境的數據插入資料庫中。 例如,當應用程式在生產環境中可用時,您可能會想要讓資料庫在數據表中包含 Department 實際的部門名稱。

在本教學課程中,您將使用移轉進行部署,但您的 Seed 方法無論如何都會插入測試數據,以便更輕鬆地查看應用程式功能的運作方式,而不需要手動插入大量數據。

  1. 將Configuration.cs檔案的內容取代為下列程式代碼,此程式代碼會將測試數據載入新資料庫中。

    namespace ContosoUniversity.Migrations
    {
       using System;
       using System.Collections.Generic;
       using System.Data.Entity.Migrations;
       using System.Linq;
       using ContosoUniversity.Models;
    
       internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
       {
          public Configuration()
          {
             AutomaticMigrationsEnabled = false;
          }
    
          protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
          {
             var students = new List<Student>
                {
                    new Student { FirstMidName = "Carson",   LastName = "Alexander", 
                        EnrollmentDate = DateTime.Parse("2010-09-01") },
                    new Student { FirstMidName = "Meredith", LastName = "Alonso",    
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Arturo",   LastName = "Anand",     
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Gytis",    LastName = "Barzdukas", 
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Yan",      LastName = "Li",        
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Peggy",    LastName = "Justice",   
                        EnrollmentDate = DateTime.Parse("2011-09-01") },
                    new Student { FirstMidName = "Laura",    LastName = "Norman",    
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Nino",     LastName = "Olivetto",  
                        EnrollmentDate = DateTime.Parse("2005-08-11") }
                };
             students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
             context.SaveChanges();
    
             var courses = new List<Course>
                {
                    new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3, },
                    new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
                    new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
                    new Course {CourseID = 1045, Title = "Calculus",       Credits = 4, },
                    new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4, },
                    new Course {CourseID = 2021, Title = "Composition",    Credits = 3, },
                    new Course {CourseID = 2042, Title = "Literature",     Credits = 4, }
                };
             courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
             context.SaveChanges();
    
             var enrollments = new List<Enrollment>
                {
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").StudentID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
             foreach (Enrollment e in enrollments)
             {
                var enrollmentInDataBase = context.Enrollments.Where(
                    s =>
                         s.Student.StudentID == e.StudentID &&
                         s.Course.CourseID == e.CourseID).SingleOrDefault();
                if (enrollmentInDataBase == null)
                {
                   context.Enrollments.Add(e);
                }
             }
             context.SaveChanges();
          }
       }
    }
    

    Seed 方法會採用資料庫內容物件做為輸入參數,而方法中的程式代碼會使用該物件將新實體新增至資料庫。 針對每個實體類型,程式代碼會建立新實體的集合、將它們新增至適當的 DbSet 屬性,然後將變更儲存至資料庫。 在每組實體之後呼叫 SaveChanges 方法並不需要如此,但這樣做可協助您找出問題的來源,如果程式代碼正在寫入資料庫時發生例外狀況。

    插入數據的一些語句會使用 AddOrUpdate 方法來執行“upsert” 作業。 Seed因為方法會隨著每個移轉一起執行,因此您不只能插入數據,因為您嘗試新增的數據列將會在第一次建立資料庫之後就已經存在。 「upsert」作業會防止當您嘗試插入已經存在的數據列時所發生的錯誤,但它 覆寫您在測試應用程式時可能所做的任何數據變更。 在某些資料表中測試數據時,您可能不想發生這種情況:在某些情況下,當您在測試時變更數據時,您希望在資料庫更新之後保留變更。 在此情況下,您想要執行條件式插入作業:只有在數據列不存在時才插入數據列。 Seed 方法會使用這兩種方法。

    傳遞至 AddOrUpdate 方法的第一個參數會指定要用來檢查數據列是否存在的屬性。 針對您提供的測試學生數據,屬性可用於此目的, LastName 因為清單中的每個姓氏都是唯一的:

    context.Students.AddOrUpdate(p => p.LastName, s)
    

    此程式代碼假設姓氏是唯一的。 如果您手動新增具有重複姓氏的學生,下次執行移轉時,將會收到下列例外狀況。

    序列包含一個以上的專案

    如需方法 AddOrUpdate 的詳細資訊,請參閱 Julie Lerman 部落格上的 EF 4.3 AddOrUpdate 方法

    新增 Enrollment 實體的程式代碼不會使用 AddOrUpdate 方法。 它會檢查實體是否已存在,並在實體不存在時插入實體。 此方法會保留您在移轉執行時對註冊等級所做的變更。 程式代碼會迴圈查看 List 的每個成員Enrollment,如果資料庫中找不到註冊,則會將註冊新增至資料庫。 第一次更新資料庫時,資料庫會是空的,因此它會新增每個註冊。

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.StudentID == e.Student.StudentID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    

    如需如何偵 Seed 錯方法以及如何處理重複數據的資訊,例如名為 「Alexander Carson」 的兩名學生,請參閱 Rick Anderson 部落格上的植入和偵錯 Entity Framework (EF) DB

  2. 組建專案。

建立和執行第一個移轉

  1. 在 [封裝管理員 控制台] 視窗中,輸入下列命令:

    add-migration InitialCreate
    update-database
    

    顯示 [封裝管理員 主控台] 視窗的螢幕快照。命令會反白顯示新增連字元移轉底線初始建立和更新連字元資料庫。

    此命令add-migration會將 [DateStamp]_InitialCreate.cs檔案新增至 Migrations 資料夾,其中包含建立資料庫的程式代碼。 第一個參數 (InitialCreate) 用於檔名,可以是您想要的任何專案;您通常會選擇一個單字或片語來摘要說明在移轉中執行的動作。 例如,您可以將稍後的移轉命名為 "AddDepartmentTable"。

    具有初始移轉的移轉資料夾

    類別 UpInitialCreate 方法會建立對應至數據模型實體集的資料庫數據表,而 Down 方法會加以刪除。 Migrations 會呼叫 Up 方法,以實作移轉所需的資料模型變更。 當您輸入命令以復原更新時,Migrations 會呼叫 Down 方法。 下列程式代碼顯示檔案的內容 InitialCreate

    namespace ContosoUniversity.Migrations
    {
        using System;
        using System.Data.Entity.Migrations;
        
        public partial class InitialCreate : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Student",
                    c => new
                        {
                            StudentID = c.Int(nullable: false, identity: true),
                            LastName = c.String(),
                            FirstMidName = c.String(),
                            EnrollmentDate = c.DateTime(nullable: false),
                        })
                    .PrimaryKey(t => t.StudentID);
                
                CreateTable(
                    "dbo.Enrollment",
                    c => new
                        {
                            EnrollmentID = c.Int(nullable: false, identity: true),
                            CourseID = c.Int(nullable: false),
                            StudentID = c.Int(nullable: false),
                            Grade = c.Int(),
                        })
                    .PrimaryKey(t => t.EnrollmentID)
                    .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
                    .ForeignKey("dbo.Student", t => t.StudentID, cascadeDelete: true)
                    .Index(t => t.CourseID)
                    .Index(t => t.StudentID);
                
                CreateTable(
                    "dbo.Course",
                    c => new
                        {
                            CourseID = c.Int(nullable: false),
                            Title = c.String(),
                            Credits = c.Int(nullable: false),
                        })
                    .PrimaryKey(t => t.CourseID);
                
            }
            
            public override void Down()
            {
                DropIndex("dbo.Enrollment", new[] { "StudentID" });
                DropIndex("dbo.Enrollment", new[] { "CourseID" });
                DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
                DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
                DropTable("dbo.Course");
                DropTable("dbo.Enrollment");
                DropTable("dbo.Student");
            }
        }
    }
    

    命令 update-databaseUp 執行 方法來建立資料庫,然後執行 Seed 方法來填入資料庫。

現在已為您的數據模型建立 SQL Server 資料庫。 資料庫的名稱是 ContosoUniversity而.mdf檔案位於您專案的 App_Data 資料夾中,因為這是您在 連接字串 中指定的。

您可以使用伺服器總管或 SQL Server 物件總管 (SSOX) 在 Visual Studio 中檢視資料庫。 在本教學課程中,您將使用 伺服器總管。 在 Visual Studio Express 2012 for Web 中, 伺服器 總管稱為 資料庫總管

  1. 從 [ 檢視] 功能表中,單擊 [伺服器總管]。

  2. 按兩下 [ 新增連線] 圖示。

    顯示 [資料庫總管] 視窗的螢幕快照。[新增連線] 圖示會反白顯示。

  3. 如果出現 [選擇數據源] 對話框的提示,請按兩下 [Microsoft SQL Server],然後按兩下 [繼續]。

    顯示 [選擇資料源] 對話框的螢幕快照。已選取Microsoft S Q L 伺服器數據源。

  4. 在 [新增連線] 對話框中,輸入 [伺服器名稱] 的 [localdb]\v11.0。 在 [選取或輸入資料庫名稱] 下,選取 [ContosoUniversity]。

    顯示 [新增連線] 對話框的螢幕快照。範例伺服器名稱和 Contoso University 資料庫會反白顯示。

  5. 按一下 [確定]

  6. 展開 [SchoolContext ],然後展開 [ 數據表]。

    顯示 [伺服器總管] 頁面的螢幕快照。[學校內容] 和 [數據表] 索引標籤會展開。

  7. 以滑鼠右鍵按兩下 Student 資料表,然後按兩下 [顯示資料表數據 ] 以查看已建立的數據行,以及插入資料表的數據列。

    學生表格

建立學生控制器和檢視

下一個步驟是在應用程式中建立 ASP.NET MVC控制器和檢視,以搭配其中一個資料表使用。

  1. 若要建立Student控制器,請以滑鼠右鍵按兩下 方案總管中的Controllers資料夾,選取[新增],然後按兩下 [控制器]。 在 [ 新增控制器] 對話框中,進行下列選取,然後按兩下 [ 新增]:

    • 控制器名稱: StudentController

    • 範本: 使用 Entity Framework 搭配讀取/寫入動作和檢視的MVC控制器。

    • 模型類: 學生(ContosoUniversity.Models)。 (如果您在下拉式清單中看不到此選項,請建置項目,然後再試一次。

    • 數據內容類別: SchoolContext (ContosoUniversity.Models)

    • 檢視: Razor (CSHTML)。 (預設值。

      Add_Controller_dialog_box_for_Student_controller

  2. Visual Studio 會 開啟 Controllers\StudentController.cs 檔案。 您會看到已建立類別變數來具現化資料庫內容物件:

    private SchoolContext db = new SchoolContext();
    

    動作Index方法會藉由讀取Students資料庫內容實例的 屬性,從 Students 實體集取得學生清單:

    public ViewResult Index()
    {
        return View(db.Students.ToList());
    }
    

    Student \Index.cshtml 檢視會在數據表中顯示此列表:

    <table>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.FirstMidName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </th>
            <th></th>
        </tr>
    
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <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>
        </tr>
    }
    
  3. 按 CTRL+F5 執行專案。

    按兩下 [ 學生] 索引標籤,以查看方法所插入的測試數據 Seed

    學生索引頁面

慣例

您必須撰寫的程式代碼數量,以便 Entity Framework 能夠為您建立完整的資料庫,因為使用 慣例,或假設 Entity Framework 所建立的程式代碼數量最少。 其中一些已經注意到:

  • 實體類別名稱的複數形式會當做數據表名稱使用。
  • 實體屬性名稱會用於資料行名稱。
  • 具名 IDclassname ID 的實體屬性會辨識為主鍵屬性。

您已瞭解可以覆寫慣例(例如,您指定不應複數的數據表名稱),您將深入瞭解慣例,以及如何在本系列稍後的 建立更複雜的數據模型 教學課程中覆寫這些慣例。 如需詳細資訊,請參閱 Code First 慣例

摘要

您現在已建立使用 Entity Framework 和 SQL Server Express 來儲存和顯示資料的簡單應用程式。 在下列教學課程中,您將瞭解如何執行基本 CRUD(建立、讀取、更新、刪除)作業。 您可以在此頁面底部留下意見反應。 請讓我們知道您喜歡本教學課程的這個部分,以及如何加以改善。

您可以在 ASP.NET 數據存取內容對應中找到其他 Entity Framework 資源的連結。