你在本教程中將創建一個簡單的大學網站。css
用戶能夠查看和更新學生信息,固然也包括教師的。下列圖表是你將建立的應用程序截屏。html
本網站的UI樣式來源於內置的模板,因此教程能夠將注意力集中在如何使用實體框架上。jquery
打開VS而且建立一個新的C#Web項目,命名爲ContosoUniversity。web
在新建ASP.Net項目對話框中,選擇MVC模板並點擊更改身分驗證按鈕,選擇無身份驗證並肯定,建立項目。數據庫
咱們將對站點目錄,佈局和主頁面作些細微簡單的改變。bootstrap
打開 _Layout.cshtml並作如下更改:瀏覽器
完成後,你的代碼應該和下列內容一致服務器
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <meta charset="utf-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>@ViewBag.Title - Contoso 大學</title> 8 @Styles.Render("~/Content/css") 9 @Scripts.Render("~/bundles/modernizr") 10 </head> 11 <body> 12 <div class="navbar navbar-inverse navbar-fixed-top"> 13 <div class="container"> 14 <div class="navbar-header"> 15 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> 16 <span class="icon-bar"></span> 17 <span class="icon-bar"></span> 18 <span class="icon-bar"></span> 19 </button> 20 @Html.ActionLink("Contoso 大學", "Index", "Home", null, new { @class = "navbar-brand" }) 21 </div> 22 <div class="navbar-collapse collapse"> 23 <ul class="nav navbar-nav"> 24 <li>@Html.ActionLink("主頁", "Index", "Home")</li> 25 <li>@Html.ActionLink("關於", "About", "Home")</li> 26 <li>@Html.ActionLink("學生", "Index", "Student")</li> 27 <li>@Html.ActionLink("教師", "Index", "Course")</li> 28 <li>@Html.ActionLink("課程", "Index", "Instructor")</li> 29 <li>@Html.ActionLink("部門", "Index", "Department")</li> 30 </ul> 31 </div> 32 </div> 33 </div> 34 <div class="container body-content"> 35 @RenderBody() 36 <hr /> 37 <footer> 38 <p>© @DateTime.Now.Year - Contoso 大學</p> 39 </footer> 40 </div> 41 42 @Scripts.Render("~/bundles/jquery") 43 @Scripts.Render("~/bundles/bootstrap") 44 @RenderSection("scripts", required: false) 45 </body> 46 </html>
在View\Home\Index.cshtml中,用下面的代碼替換原有的:架構
1 @{ 2 ViewBag.Title = "Home Page"; 3 } 4 5 <div class="jumbotron"> 6 <h1>Contoso 大學</h1> 7 </div> 8 9 <div class="row"> 10 <div class="col-md-4"> 11 <h2>歡迎訪問Contoso大學</h2> 12 <p> 13 Contoso 大學是一個示例應用程序,演示瞭如何在MVC5中如何使用實體框架6來創建一個Web應用程序。 14 </p> 15 </div> 16 <div class="col-md-4"> 17 <h2>從頭創建</h2> 18 <p>你能夠跟隨教程來一步步創建該應用程序。</p> 19 <p><a class="btn btn-default" href="http://www.cnblogs.com/Bce-/p/3684643.html">查看教程 »</a></p> 20 </div> 21 <div class="col-md-4"> 22 <h2>直接下載</h2> 23 <p>你能夠從微軟代碼庫中直接下載已完成的項目</p> 24 <p><a class="btn btn-default" href="http://code.msdn.microsoft.com/ASPNET-MVC-Application-b01a9fe8">Download »</a></p> 25 </div> 26 </div>
按下Ctrl+F5運行網站,你能夠看到主頁及菜單。框架
在工具菜單中,點擊NuGet程序包管理器,點擊程序包管理器控制檯。
在控制檯中,輸入如下命令並執行:
Install-Package EntityFramework
你能夠看到實體框架包被添加到項目中。
下面你將創建用於大學網站的實體類。你將從如下三個類開始:
注意Student和Enrollment存在一對多的關聯關係。一樣Course和Enrollment也是如此。換句話說,一個學生能夠參加任意數量的課程,而一門課程也被任意數量的學生參加。
在下面的章節中咱們將開始建立這些實體。
注意:若是你在這些實體類所有建立完成以前嘗試運行項目,你將會獲得編譯器錯誤的提示。
在Models文件夾下,建立Student類並使用如下的代碼替換:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace ContosoUniversity.Models 7 { 8 public class Student 9 { 10 public int ID { get; set; } 11 public string LastName { get; set; } 12 public string FirstMidName { get; set; } 13 public DateTime EnrollmentDate { get; set; } 14 15 public virtual ICollection<Enrollment> Enrollments { get; set; } 16 } 17 }
ID屬性將成爲數據表中對應該類的主鍵列。默認狀況下,實體框架將命名爲ID或類名+ID的屬性用做主鍵列。
Enrollments屬性是一個導航屬性。導航屬性創建本實體相關的其餘實體之間的聯繫。在本例中,一個Student實體的Enrollments屬性將容納全部與Student實體相關聯的Entollment實體。換句話說,若是一個Student在數據庫中有兩個相關的Enrollment行(列使用使用該學生的主鍵值做爲外鍵),即Student實體的Enrollments屬性將包含這兩個關聯的Enrollment實體。
導航屬性一般被定義爲virtual,使他們能得到某些實體框架的功能,好比延遲加載的優點。(關於延遲加載咱們將在後面解釋)
若是某個導航屬性能夠包含多個實體(如多對多或一對多關係),它的類型必須能夠進行增刪改操做,好比ICollection。
在Models文件夾中,建立Enrollment類並用下面的代碼替換現有的:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace ContosoUniversity.Models 7 { 8 public enum Grade 9 { 10 A, B, C, D, F 11 } 12 13 14 public class Enrollment 15 { 16 public int EnrollmentID { get; set; } 17 public int CourseID { get; set; } 18 public int StudentID { get; set; } 19 public Grade? Grade { get; set; } 20 21 public virtual Course Course { get; set; } 22 public virtual Student Student { get; set; } 23 } 24 }
EnrollmentID屬性將做爲主鍵,它使用了類名+ID的模式而不是你在Student中直接使用ID自己的方法。一般狀況下你應當在這兩種方式中選擇一種做爲整個項目的統一命名方式,在這裏咱們只是演示了這兩種方式的使用。在後面的教程中你將看到如何使用不帶類名的ID從而更容易地在數據模型中實現繼承。
Grade屬性是一個枚舉。屬性後的問號表示這是一個可爲空的屬性。Null表示一個未知或沒有分配的級別。
StudentID是一個外鍵,相應的導航屬性是Student。一個Enrollment實體關聯到一個Student實體。因此屬性只能容納一個Student實體(而不像以前的Student.Enrollments導航屬性,它能夠容納多個Enrollments實體)。
一樣CourseID也是一個外鍵,關聯到一個Course實體。
若是一個屬性的命名方式爲導航屬性名+主鍵屬性名,實體框架便會將該屬性視爲外鍵屬性。(例如,Student實體的主鍵爲ID,則StudentID被視爲爲Student導航屬性的外鍵)。外鍵的屬性也能夠命名爲簡單的主鍵屬性名(例如,Course實體的主鍵爲CourseID)。
在Models文件夾中建立Course類並使用如下的代碼替換模板代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel.DataAnnotations.Schema; 4 using System.Linq; 5 using System.Web; 6 7 namespace ContosoUniversity.Models 8 { 9 public class Course 10 { 11 [DatabaseGenerated(DatabaseGeneratedOption.None)] 12 public int CourseID { get; set; } 13 public string Title { get; set; } 14 public int Credits { get; set; } 15 16 public virtual ICollection<Enrollment> Enrollments { get; set; } 17 } 18 }
Enrollments屬性是一個導航屬性。一個Course實體能夠和任意個Enrollment實體關聯。
咱們會在後面的教程中介紹更多的關於DatabaseGenerated特性。該特性可讓你來輸入該實體的主鍵值,而不是讓數據庫自動生成它。
在一個數據模型中負責協調實體框架功能的主類被稱爲數據庫上下文類。您能夠經過派生自System.Data.Entity.DbContext類來建立。你能夠在代碼中指定那些實體被包含在數據模型中。您能夠能夠自定義某些實體框架的行爲。在本項目中,上下文類被命名爲SchoolContext。
右鍵單擊解決資源方案管理器中的項目,點擊添加,點擊新建文件夾。將新文件夾命名爲DAL(數據訪問層)。在該文件夾中建立一個SchoolContext類並使用如下代碼替換模板代碼:
1 using ContosoUniversity.Models; 2 using System; 3 using System.Collections.Generic; 4 using System.Data.Entity; 5 using System.Data.Entity.ModelConfiguration.Conventions; 6 using System.Linq; 7 using System.Web; 8 9 namespace ContosoUniversity.DAL 10 { 11 public class SchoolContext : DbContext 12 { 13 public SchoolContext() : base("SchoolContext") { } 14 15 public DbSet<Student> Students { get; set; } 16 public DbSet<Enrollment> Entollments { get; set; } 17 public DbSet<Course> Courses { get; set; } 18 19 protected override void OnModelCreating(DbModelBuilder modelBuilder) 20 { 21 modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 22 } 23 } 24 }
這段代碼爲每一個實體集合建立了一個DbSet屬性。在實體框架中,一個實體集對應數據庫中的表,一個實體對應數據表中的一行。
你能夠省略DbSet<Enrollment>
和DbSet<Course>,實體框架將自動把它們包含進來。由於Student實體引用了Enrollment實體,而且Enrollment實體引用了Course實體。
鏈接字符串(稍後將被添加到web.config文件中)的名稱被傳遞給構造函數。
1 public SchoolContext() : base("SchoolContext") 2 { 3 }
你一樣能夠經過傳遞鏈接字符串而不是存儲在web.config文件的鏈接字符串名稱自己來指定鏈接。若是你不指定鏈接字符串或一個明確的名稱,實體框架將假定鏈接字符串名稱和類名稱一致,即在本例中,默認的鏈接字符串名稱爲SchoolContext,同你顯示聲明的一致。
OnModelCreating方法中的modelBuilder.Convertions.Remove被用來防止生成複數表名。若是你不這樣作,在數據庫中生成的數據表將被命名爲Students,Courses及Entrollments。相反,在本例中咱們的表名是Student,Course及Enrollment。對於表名稱是否應該使用複數或單數命名模式並無明確的要求。在本教程中咱們將使用單數形式。重要的一點是,你能夠選擇任意的命名方式——經過是否註釋掉該行代碼。
當你運行程序時,實體框架能夠自動建立(或自動刪除並從新建立)數據表。你能夠指定這應該在每次程序運行時進行或僅當模型發生了變化而不與現有的數據庫同步時才進行。你也能夠寫一個Seed方法,以便在數據庫初始化後自動填充測試數據到新的數據表中。
默認的行爲是隻有當該數據庫不存在時才建立(當數據庫已經存在時會拋出一個異常)。在本節中你將指定在每次模型發生變化時都刪除舊數據庫並創建一個新的。在本例中這樣作是適當的。Seed方法將在從新建立後自動填充測試數據。而在生產中一般不但願這樣作從而丟失數據庫中的全部數據。稍後您將看到如何使用Code First Migration來改變數據庫架構,而不是刪除並從新建立。
在DAL文件夾中,建立一個SchoolInitializer類並使用如下代碼替換默認的:
1 using ContosoUniversity.Models; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Web; 6 7 namespace ContosoUniversity.DAL 8 { 9 public class SchoolInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<SchoolContext> 10 { 11 protected override void Seed(SchoolContext context) 12 { 13 var students = new List<Student> 14 { 15 new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")}, 16 new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")}, 17 new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")}, 18 new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")}, 19 new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")}, 20 new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")}, 21 new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")}, 22 new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")} 23 }; 24 25 students.ForEach(s => context.Students.Add(s)); 26 context.SaveChanges(); 27 var courses = new List<Course> 28 { 29 new Course{CourseID=1050,Title="Chemistry",Credits=3,}, 30 new Course{CourseID=4022,Title="Microeconomics",Credits=3,}, 31 new Course{CourseID=4041,Title="Macroeconomics",Credits=3,}, 32 new Course{CourseID=1045,Title="Calculus",Credits=4,}, 33 new Course{CourseID=3141,Title="Trigonometry",Credits=4,}, 34 new Course{CourseID=2021,Title="Composition",Credits=3,}, 35 new Course{CourseID=2042,Title="Literature",Credits=4,} 36 }; 37 courses.ForEach(s => context.Courses.Add(s)); 38 context.SaveChanges(); 39 var enrollments = new List<Enrollment> 40 { 41 new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A}, 42 new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C}, 43 new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B}, 44 new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B}, 45 new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F}, 46 new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F}, 47 new Enrollment{StudentID=3,CourseID=1050}, 48 new Enrollment{StudentID=4,CourseID=1050,}, 49 new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F}, 50 new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C}, 51 new Enrollment{StudentID=6,CourseID=1045}, 52 new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A}, 53 }; 54 enrollments.ForEach(s => context.Enrollments.Add(s)); 55 context.SaveChanges(); 56 } 57 } 58 }
Seed方法將數據庫的上下文對象做爲輸入參數,並在方法中的代碼使用該上下文對象將新的實體添加到數據庫中。對於每一個實體模型,代碼建立新的實體集合添加他們到相應的DbSet屬性,而後將更改保存到數據庫。它並非必須在每組實體後當即調用SaveChanges方法。但這樣作有助於你在發生數據庫寫入異常時快速找到問題的根源。
向web.config中添加一個元素來告訴實體框架你將使用初始化類,好比下面的例子:
context 的Type屬性指定了上下文的類名。你應當使用完整的類名和程序集名。一樣databaseInitializer的Type指定了初始化類的名稱。(若是你不想使用EF初始化,你能夠在上下文元素中設置disableDatabaseInitialization="true"
)。
做爲一種在web.config中設置初始值設定項的替代方法,你能夠經過在Global.asax.cs中Application_Start方法中增長Database.SetInitializer語句來實現一樣的功能。
如今應用程序已經設置爲在程序首次運行時,對模型和數據庫中的表進行比較,若是有區別,應用程序刪除並從新建立該數據庫。
注意:當你將應用程序部署到生產環境中時,你必須刪除或禁用數據庫從新建立代碼,後面的教程會演示這一點。
LocalDB是SQL Server Express的一個輕量版本,很是適合用來進行本地測試,但不建議在生產中使用。
打開應用程序的web.config文件,添加數據庫鏈接字符串,以下面的例子:
你添加的數據庫鏈接字符串指定實體框架使用LocalDb做爲數據庫引擎,創建一個名爲ContosoUniversity1.mdf的數據庫(當前數據庫還不存在,EF將自動建立它)。若是你想在你的App_data中存放數據庫文件,您能夠添加AttachDBFilename=|DataDirectory|\ContosoUniversity1.mdf到鏈接字符串。
如今將建立一個網頁來顯示數據,並在請求數據的過程當中自動觸發數據庫建立。你首先須要建立一個新的控制器,但在此以前,生成一次項目以將實體類提供給MVC控制器腳手架模型和上下文類。
private SchoolContext db = new SchoolContext();
1 public ActionResult Index() 2 { 3 return View(db.Students.ToList()); 4 }
Student\Index.cshtml視圖將列表顯示在表格中:
1 @model IEnumerable<ContosoUniversity.Models.Student> 2 3 @{ 4 ViewBag.Title = "Index"; 5 } 6 7 <h2>Index</h2> 8 9 <p> 10 @Html.ActionLink("Create New", "Create") 11 </p> 12 <table class="table"> 13 <tr> 14 <th> 15 @Html.DisplayNameFor(model => model.LastName) 16 </th> 17 <th> 18 @Html.DisplayNameFor(model => model.FirstMidName) 19 </th> 20 <th> 21 @Html.DisplayNameFor(model => model.EnrollmentDate) 22 </th> 23 <th></th> 24 </tr> 25 26 @foreach (var item in Model) { 27 <tr> 28 <td> 29 @Html.DisplayFor(modelItem => item.LastName) 30 </td> 31 <td> 32 @Html.DisplayFor(modelItem => item.FirstMidName) 33 </td> 34 <td> 35 @Html.DisplayFor(modelItem => item.EnrollmentDate) 36 </td> 37 <td> 38 @Html.ActionLink("Edit", "Edit", new { id=item.ID }) | 39 @Html.ActionLink("Details", "Details", new { id=item.ID }) | 40 @Html.ActionLink("Delete", "Delete", new { id=item.ID }) 41 </td> 42 </tr> 43 } 44 45 </table>
當你運行學生信息頁面而且程序嘗試存取數據時,實體框架會檢查到沒有已存在的數據庫並嘗試建立一個。而後運行Seed方法向數據庫中填充數據。
你可使用服務器資源管理器或SQL Server對象管理器來查看數據庫,在本教程中,咱們將使用服務器資源管理器。
ContosoUniversity1.mdf 和 .ldf 數據庫文件一般存放在C:\User\你的用戶名文件夾中。
因爲你使用了DropCreateDatabaseIfModelChanges初始化器,你如今能夠對Student類作一些改變,從新運行應用程序。數據庫會自動從新創建數據表來匹配你所作出的改變。好比若是你添加了EmailAddress屬性到Student類中,從新運行應用程序並打開Student頁面,而後關閉頁面,檢查數據庫表中的數據,你會看到新的EmailAddress列。
由於使用了約定,你用於編寫創建一個完整數據庫的代碼量已經下降到了最少。這些約定已經在以前的教程中被你使用到,或許你沒有意識到你正在使用它們,包括:
你已經看到,約定能夠被覆蓋。例如指定表的名稱不該當使用複數形式,你會看到之後如何明確標記屬性做爲外鍵屬性。你將在後面的教程中瞭解更多有關約定及如何重寫它們。
如今,您已經建立了一個使用實體框架和SQL Server Express LocalDB來存儲和顯示數據的簡單Web應用程序,在後面的教程中,您將學習如何執行基本的CRUD操做。