共用方式為


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

作者 :Tom Dykstra

注意

本教學課程系列的較新版本適用於 Visual Studio 2013、Entity Framework 6 和 MVC 5。

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

Code First

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

MVC

範例應用程式建置在 ASP.NET MVC上。 如果您想要使用 ASP.NET Web Forms 模型,請參閱模型系結和 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 2012Express for Web,以及自 2013 年 7 月起安裝的最新更新和適用於 .NET 的 Azure SDK。 您可以使用下列連結來取得所有項目:

Azure SDK for .NET (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.cs 中,將 Action 方法中的 IndexViewBag.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 會將名為 IDclassnameID 的屬性解譯為主鍵。

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。下一個教學課程中無) ] 屬性。 基本上,此屬性可讓您為課程輸入主索引鍵,而非讓資料庫產生它。

建立資料庫內容

協調指定數據模型的 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.RemoveOnModelCreating 方法中的語句可防止數據表名稱進行複數化。 如果您未這麼做,產生的數據表會命名 Students為、 CoursesEnrollments。 相反地,資料表名稱會是 StudentCourseEnrollment。 針對是否要複數化資料表名稱,開發人員並沒有共識。 本教學課程使用單一窗體,但重點是您可以藉由包含或省略這一行程式代碼來選取您偏好的窗體。

SQL Server Express LocalDB

LocalDB 是輕量型版本的 SQL Server Express Database Engine,可視需要啟動並在使用者模式中執行。 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 和舊版中,預設會隨 Visual Studio 安裝不含 LocalDB) 的 SQL Server Express (;如果您使用 Visual Studio 2010,則必須手動安裝它。

在本教學課程中,您將使用LocalDB,讓資料庫可以儲存在 App_Data 資料夾中作為 .mdf 檔案。 開啟根 Web.config檔案,並將新的 連接字串 新增至connectionStrings集合,如下列範例所示。 (請務必更新根項目資料夾中 的Web.config 檔案。另外還有 Web.config 檔案位於您不需要 update 的 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。 您新增的 連接字串 會指定位於App_Data資料夾中名為 ContosoUniversity.mdf 的 LocalDB 資料庫。 如需詳細資訊,請參閱 SQL Server ASP.NET Web 應用程式的連接字串

您實際上不需要指定 連接字串。 如果您沒有提供 連接字串,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 資料夾,並將 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 方法會在 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 方法以及如何處理重複數據的資訊,例如名為 「在 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-database命令會Up執行 方法來建立資料庫,然後執行 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 Server 數據源。

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

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

  5. 按一下 [確定]。

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

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

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

    學生表格

建立學生控制器和檢視

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

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

    • 控制器名稱: StudentController

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

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

    • 資料內容類別: SchoolContext (ContosoUniversity.Models)

    • 檢視: Razor (CSHTML) 。 (default.)

      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。 其中有些已經注意:

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

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

摘要

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

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