為 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 First、Model 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 應用程式
您在這些教學課程中會建置的應用程式為一個簡單的大學網站。
使用者可以檢視和更新學生、課程和教師資訊。 以下是您會建立的幾個畫面。
此網站的 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)。
在 [ 新增 ASP.NET MVC 4 專案 ] 對話框中,選取 [因特網應用程式 ] 範本。
保留選取 [ Razor 檢視引擎],然後清除 [ 建立單元測試專案 ] 複選框。
按一下 [確定]。
設定網站樣式
一些簡單的變更會設定網站的功能表、配置和首頁。
開啟 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>© @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中Index
,將 Action 方法中的 值ViewBag.Message
變更為 “Welcome to Contoso University!”,如下列範例所示:
public ActionResult Index()
{
ViewBag.Message = "Welcome to Contoso University";
return View();
}
按 CTRL+F5 以執行網站。 您會看到帶有主選單的主頁。
建立數據模型
接下來您會為 Contoso 大學應用程式建立實體類別。 您將從以下三個實體開始:
在 Student
和 Enrollment
實體之間存在一對多關聯性,Course
與 Enrollment
實體之間也存在一對多關聯性。 換句話說,一位學生可以註冊並參加任何數目的課程,而一個課程也可以有任何數目的學生註冊。
在下節中,您會為這些實體建立各自的類別。
注意
如果您在完成所有這些實體類別的建立之前嘗試編譯項目,則會出現編譯器錯誤。
學生實體
在 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 會將名為 ID
或 classname ID
的屬性解譯為主鍵。
Enrollments
屬性為導覽屬性。 導覽屬性會保留與此實體相關的其他實體。 在這種情況下,Student
實體的 Enrollments
屬性將保留與 Enrollment
實體相關的所有 Student
實體。 換句話說,如果資料庫中的給定Student
行有兩個相關Enrollment
行 (StudentID
在其外鍵列中包含該學生的主鍵值的行Student
),則 Enrollments
Enrollment
實體的導航屬性將包含這兩個實體。
導航屬性通常被定義為 virtual
,使得它們可以利用某些實體框架功能,例如延遲載入。 (稍後會在 中 說明延遲載入閱讀本系列稍後的相關數據 教學課程。
若導覽屬性可保有多個實體 (例如在多對多或一對多關聯性中的情況),其類型必須為一個清單,使得實體可以在該清單中新增、刪除或更新,例如 ICollection
。
註冊實體
在 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。 空成績與零成績不同 - 空意味著成績未知或尚未分配。
StudentID
屬性是外部索引鍵,對應的導覽屬性是 Student
。 Enrollment
實體與一個 Student
實體關聯,因此屬性僅能保有單一 Student
實體 (不像您先前看到的 Student.Enrollments
導覽屬性可保有多個 Enrollment
實體)。
CourseID
屬性是外部索引鍵,對應的導覽屬性是 Course
。 一個 Enrollment
實體與一個 Course
實體建立關聯。
Course 實體
在 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)] 屬性。 基本上,此屬性可讓您為課程輸入主索引鍵,而非讓資料庫產生它。
建立資料庫內容
協調給定資料模型的實體框架功能的主要類別是資料庫上下文類別。 您可以透過從 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 屬性。 在實體框架術語中,實體集通常對應於資料庫表,實體對應於表中的一行。
OnModelCreating 方法中的 modelBuilder.Conventions.Remove
語句防止表名採用複數形式。 如果您未這麼做,產生的數據表會命名為 Students
、 Courses
和 Enrollments
。 相反,表名稱將為 Student
、Course
和 Enrollment
。 針對是否要複數化資料表名稱,開發人員並沒有共識。 本教學課程使用單數形式,但重要的一點是,您可以透過包含或省略這行程式碼來選擇您喜歡的形式。
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
針對此專案)。 您新增的 連接字串 會指定名為localDB資料庫ContosoUniversity.mdf位於 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 移轉
在 [工具] 功能表按一下 [NuGet 套件管理員],然後按一下 [套件管理員主控台]。
在
PM>
提示字元中輸入下列命令:enable-migrations -contexttypename SchoolContext
此命令會在 ContosoUniversity 專案中建立 Migrations 資料夾,並將該資料夾 放入您可以編輯以設定 Migrations 的Configuration.cs 檔案。
類別
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
方法無論如何都會插入測試資料,以便更輕鬆地了解應用程式功能如何運作,而無需手動插入大量資料。
將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」作業會防止您嘗試插入已存在的列時會發生的錯誤,但會覆寫您在測試應用程式時可能已完成的任何資料變更。 表格中有測試資料時,您可能不希望發生上述情況:某些案例中,如果您在測試時變更資料,可能會希望資料庫更新後變更仍保留下來。 在這種情況下,您想要執行條件插入操作:僅當行尚不存在時才插入行。 種子方法同時使用這兩種方法。傳遞給 AddOrUpdate 方法的第一個參數指定用於檢查行是否已存在的屬性。 對於您提供的測試學生資料,
LastName
屬性可用於此目的,因為列表中的每個姓氏都是唯一的:context.Students.AddOrUpdate(p => p.LastName, s)
此代碼假定姓氏是唯一的。 如果您手動新增具有重複姓氏的學生,下次執行移轉時,將會收到下列例外狀況。
序列包含多個元素
有關
AddOrUpdate
方法的詳細信息,請參閱 Julie Lerman 部落格上的 Take care with EF 4.3 AddOrUpdate Method。新增
Enrollment
實體的程式代碼不會使用AddOrUpdate
方法。 它檢查實體是否已存在,如果不存在則插入該實體。 此方法會保留您在移轉執行時對註冊等級所做的變更。 該程式碼循環遍歷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 。組建專案。
建立和執行第一個移轉
在 [封裝管理員 控制台] 視窗中,輸入下列命令:
add-migration InitialCreate update-database
此命令
add-migration
會將 [DateStamp]_InitialCreate.cs檔案新增至 Migrations 資料夾,其中包含建立資料庫的程式代碼。 第一個參數 (InitialCreate)
用於檔名,可以是您想要的任何專案;您通常會選擇一個單字或片語來摘要說明在移轉中執行的動作。 例如,您可以將稍後的移轉命名為 "AddDepartmentTable"。InitialCreate
類別的Up
方法會建立與資料模型實體集對應的資料庫表,並且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 中, 伺服器 總管稱為 資料庫總管。
從 [ 檢視] 功能表中,單擊 [伺服器總管]。
按兩下 [ 新增連線] 圖示。
如果出現 [選擇數據源] 對話框的提示,請按兩下 [Microsoft SQL Server],然後按兩下 [繼續]。
在 [新增連線] 對話框中,輸入 [伺服器名稱] 的 [localdb]\v11.0。 在 [選取或輸入資料庫名稱] 下,選取 [ContosoUniversity]。
按一下 [確定]。
展開 [SchoolContext ],然後展開 [ 數據表]。
右鍵點擊 Student 資料表,然後按一下顯示表資料以查看已建立的列以及插入到表中的行。
建立學生控制器和檢視
下一個步驟是在應用程式中建立 ASP.NET MVC控制器和檢視,以搭配其中一個資料表使用。
若要建立
Student
控制器,請以滑鼠右鍵按兩下 方案總管中的Controllers資料夾,選取[新增],然後按兩下 [控制器]。 在 [ 新增控制器] 對話框中,進行下列選取,然後按兩下 [ 新增]:控制器名稱: StudentController。
範本: 使用 Entity Framework 搭配讀取/寫入動作和檢視的MVC控制器。
模型類別:Student (ContosoUniversity.Models)。 (如果您在下拉清單中沒有看到此選項,請建立專案並重試。)
數據內容類別: SchoolContext (ContosoUniversity.Models)。
檢視:Razor (CSHTML)。 (預設值)。
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> }
按 CTRL+F5 執行專案。
按一下學生標籤以查看
Seed
方法插入的測試資料。
慣例
您必須撰寫的程式代碼數量,以便 Entity Framework 能夠為您建立完整的資料庫,因為使用 慣例,或假設 Entity Framework 所建立的程式代碼數量最少。 其中一些已經注意到:
- 實體類別名稱的複數形式用作表格名稱。
- 實體屬性名稱會用於資料行名稱。
- 命名
ID
或 類別名稱ID
的實體屬性被辨識為主鍵屬性。
您已瞭解可以覆寫慣例(例如,您指定不應複數的數據表名稱),您將深入瞭解慣例,以及如何在本系列稍後的 建立更複雜的數據模型 教學課程中覆寫這些慣例。 如需詳細資訊,請參閱 Code First 慣例。
摘要
您現在已建立使用 Entity Framework 和 SQL Server Express 來儲存和顯示資料的簡單應用程式。 在下列教學課程中,您將瞭解如何執行基本 CRUD(建立、讀取、更新、刪除)作業。 您可以在此頁面底部留下意見反應。 請讓我們知道您喜歡本教學課程的這個部分,以及如何加以改善。
您可以在 ASP.NET 數據存取內容對應中找到其他 Entity Framework 資源的連結。