近期學習MVC5+EF6,找到了Microsoft的原文,一個很是棒的系列,Getting Started with Entity Framework 6 Code First using MVC 5,網址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application。css
這個系列的原文,能夠上面網址找到。我也從網上找到了相關的譯文。申明,這些譯文,我不是原創,而是從網上找來的,爲避免下次還要網上查詢,現將這些譯文整理放在上面。之後找時間將原文地址附上。html
MVC5+EF6--1 建立Entity Framework數據模型jquery
網址:web
Contoso University示例網站演示如何使用Entity Framework 5建立ASP.NET MVC 4應用程序。sql
Entity Framework有三種處理數據的方式: Database First, Model First, and Code First. 本指南使用代碼優先。其它方式請查詢資料。數據庫
示例程序是爲Contoso University創建一個網站。功能包括:學生管理、課程建立、教師分配。 本系列指南逐步講述如何實現這一網站程序。express
本示例程序基於 ASP.NET MVC.若是使用 ASP.NET Web Forms model, 請查看 Model Binding and Web Forms系列指南和 ASP.NET Data Access Content Map.編程
若有問題,可在這些討論區提問: ASP.NET Entity Framework forum, the Entity Framework and LINQ to Entities forum, or StackOverflow.com.mvc
(此指南的舊版本請查看 the EF 4.1 / MVC 3 e-book.) app
本指南將建立一個簡單的大學網站.
用戶可查看或更新學生、課程、教師的信息,如下是相關截圖:
UI風格延續了默認模板的風格,以便更多關注於如何使用Entity Framework。
需求
使用 Visual Studio 2012 or Visual Studio 2012 Express for Web, 可從如下連接獲取相關需求軟件:
Windows Azure SDK for Visual Studio 2012
若是已經安裝 Visual Studio,此連接將只安裝缺乏的組件.若是沒有Visual Studio, 將安裝Visual Studio 2012 Express for Web. 你也可以使用Visual Studio 2013,但一些步驟和截圖有所不一樣.
若使用 Visual Studio 2010,須要安裝MVC 4 和 SQL Server LocalDB.
建立程序以下:
選擇 Internet Application template.
選擇 Razor
點擊OK.
菜單、佈局有少量變更.
打開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>
上面作了兩點改變:
在Views\Home\Index.cshtml, 替換爲以下代碼:
@{
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, 把 ViewBag.Message
值替換爲 "Welcome to Contoso University!":
public ActionResult Index()
{
ViewBag.Message = "Welcome to Contoso University";
return View();
}
CTRL+F5 運行,界面以下.
先建立以下三個數據模型:
Student
and Enrollment
實體是一對多關係,, Course
and 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或者類名ID的屬性設爲主鍵。
Enrollments
是一個導航屬性。導航屬性記錄和本實體相關的其它實體。在本例中,Enrollments
屬性記錄和 Student
屬性相關的Enrollment。.若是數據庫中某Student
記錄和
兩條Enrollment
記錄
相關。(這兩條記錄的 StudentID
外鍵值等於該Student的StudentID
)
,那麼Student
實體的 Enrollments
導航屬性將包含這兩個 Enrollment
實體.
Navigation properties 常定義爲virtual
以便發揮Entity Framework的功能,如 lazy loading. (在 Reading Related Data 部分將詳細講述延遲加載).
若是navigation property 包含多記錄 (如 many-to-many or one-to-many 關係), 類型最好是列表類型,如 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
屬性是 nullable.
StudentID
property 是外鍵, 相應的導航屬性是 Student
.一個 Enrollment
實體和一個 Student
實體相關,
CourseID
property是外鍵, 相應的導航屬性是 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)]
特性進行講解。 簡而言之,此特性代表主鍵由你賦值而非數據庫自動生成。
將 Entity Framework 功能和給定數據模型相關聯的類是 database context class. 此類繼承自 System.Data.Entity.DbContext class.代碼代表數據模型包含了哪些實體類型.本項目中數據上下文類名爲 SchoolContext
.
建立 DAL文件夾 (for Data Access Layer). 在此文件夾建立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
語句阻止表名使用實體的複數形式,若是沒有此語句,則生成的數據表分別是 Students
, Courses
, andEnrollments
. 使用此語句,表名將和實體名同樣 Student
, Course
, and Enrollment
. 這和編程風格相關,至因而否使用複數取決於你本身。
LocalDB 是一個輕量級的SQL Server。這裏不作翻譯介紹。
打開根目錄下的 Web.config 文件,在 connectionStrings
處添加鏈接字符串以下,(注意,若是沒有localdb,而使用SQL Server或者Express版本,請修改鏈接字符串)
<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尋找和數據上下文類同名的鏈接字符串 (SchoolContext
for this project). 更多鏈接字符串信息,請查看 SQL Server Connection Strings for ASP.NET Web Applications.
也可不添加鏈接字符串,由程序自動生成。但會致使數據庫文件沒有放在程序的 App_data文件夾下,更多信息請查看 Code First to a New Database.
connectionStrings
集合默認包含一個名爲 DefaultConnection
的鏈接字符串,是用來鏈接
membership database. 這裏不會用到。兩條鏈接字符串惟一不一樣之處是數據庫名字不一樣
在程序初期,數據模型常常發生變更,每次變更就會致使和數據庫不一致。可將Entity Framework配置爲變更後自動重建數據庫。但在程序使用以後若是發生變更,更但願是更新數據庫而非重建(重建致使數據丟失)。 Migrations 功能使得代碼優先方式下更新數據庫。若是但願重建可以使用DropCreateDatabaseIfModelChanges實現每次變更後重建數據庫。. 本例中咱們直接使用Migration方法,更多信息請查看 Code First Migrations.
PM>
提示符下輸入以下命令:enable-migrations -contexttypename SchoolContext
命令將建立 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
方法使得可設置自動插入到數據庫中的數據
爲了便於測試,咱們在Seed中添加一些數據
2. namespace ContosoUniversity.Migrations
3. {
4. using System;
5. using System.Collections.Generic;
6. using System.Data.Entity.Migrations;
7. using System.Linq;
8. using ContosoUniversity.Models;
9.
10. internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
11. {
12. public Configuration()
13. {
14. AutomaticMigrationsEnabled = false;
15. }
16.
17. protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
18. {
19. var students = new List<Student>
20. {
21. new Student { FirstMidName = "Carson", LastName = "Alexander",
22. EnrollmentDate = DateTime.Parse("2010-09-01") },
23. new Student { FirstMidName = "Meredith", LastName = "Alonso",
24. EnrollmentDate = DateTime.Parse("2012-09-01") },
25. new Student { FirstMidName = "Arturo", LastName = "Anand",
26. EnrollmentDate = DateTime.Parse("2013-09-01") },
27. new Student { FirstMidName = "Gytis", LastName = "Barzdukas",
28. EnrollmentDate = DateTime.Parse("2012-09-01") },
29. new Student { FirstMidName = "Yan", LastName = "Li",
30. EnrollmentDate = DateTime.Parse("2012-09-01") },
31. new Student { FirstMidName = "Peggy", LastName = "Justice",
32. EnrollmentDate = DateTime.Parse("2011-09-01") },
33. new Student { FirstMidName = "Laura", LastName = "Norman",
34. EnrollmentDate = DateTime.Parse("2013-09-01") },
35. new Student { FirstMidName = "Nino", LastName = "Olivetto",
36. EnrollmentDate = DateTime.Parse("2005-08-11") }
37. };
38. students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
39. context.SaveChanges();
40.
41. var courses = new List<Course>
42. {
43. new Course {CourseID = 1050, Title = "Chemistry", Credits = 3, },
44. new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
45. new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
46. new Course {CourseID = 1045, Title = "Calculus", Credits = 4, },
47. new Course {CourseID = 3141, Title = "Trigonometry", Credits = 4, },
48. new Course {CourseID = 2021, Title = "Composition", Credits = 3, },
49. new Course {CourseID = 2042, Title = "Literature", Credits = 4, }
50. };
51. courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
52. context.SaveChanges();
53.
54. var enrollments = new List<Enrollment>
55. {
56. new Enrollment {
57. StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
58. CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID,
59. Grade = Grade.A
60. },
61. new Enrollment {
62. StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
63. CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID,
64. Grade = Grade.C
65. },
66. new Enrollment {
67. StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
68. CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID,
69. Grade = Grade.B
70. },
71. new Enrollment {
72. StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
73. CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID,
74. Grade = Grade.B
75. },
76. new Enrollment {
77. StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
78. CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID,
79. Grade = Grade.B
80. },
81. new Enrollment {
82. StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
83. CourseID = courses.Single(c => c.Title == "Composition" ).CourseID,
84. Grade = Grade.B
85. },
86. new Enrollment {
87. StudentID = students.Single(s => s.LastName == "Anand").StudentID,
88. CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
89. },
90. new Enrollment {
91. StudentID = students.Single(s => s.LastName == "Anand").StudentID,
92. CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
93. Grade = Grade.B
94. },
95. new Enrollment {
96. StudentID = students.Single(s => s.LastName == "Barzdukas").StudentID,
97. CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
98. Grade = Grade.B
99. },
100. new Enrollment {
101. StudentID = students.Single(s => s.LastName == "Li").StudentID,
102. CourseID = courses.Single(c => c.Title == "Composition").CourseID,
103. Grade = Grade.B
104. },
105. new Enrollment {
106. StudentID = students.Single(s => s.LastName == "Justice").StudentID,
107. CourseID = courses.Single(c => c.Title == "Literature").CourseID,
108. Grade = Grade.B
109. }
110. };
111.
112. foreach (Enrollment e in enrollments)
113. {
114. var enrollmentInDataBase = context.Enrollments.Where(
115. s =>
116. s.Student.StudentID == e.StudentID &&
117. s.Course.CourseID == e.CourseID).SingleOrDefault();
118. if (enrollmentInDataBase == null)
119. {
120. context.Enrollments.Add(e);
121. }
122. }
123. context.SaveChanges();
124. }
125. }
}
因爲此方法在建立或更新後調用,爲了不屢次插入同一數據,調用AddOrUpdate方法,第一個參數用來檢查數據是否已經存在。
context.Students.AddOrUpdate(p => p.LastName, s)
關於更多AddOrUpdate信息,請查看 Take care with EF 4.3 AddOrUpdate Method .
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中問題的調試,請查看 Seeding and Debugging Entity Framework (EF) DBs .
2. add-migration InitialCreate
update-database
add-migration
命令將添加 [DateStamp]_InitialCreate.cs 文件到Migrations文件夾,文件中包含數據庫建立初始化信息。第一個參數 (InitialCreate)
做爲文件名,前面會加上時間戳.
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");
}
}
}
The update-database
運行文件中的 Up
方法建立數據庫,而後調用 Seed
方法.
名爲 ContosoUniversity的數據庫將被建立, .mdf文件被存放在 App_Data 文件夾,如你在鏈接字符串指定的一致.
如下步驟是在VS中查看數據庫的操做,按圖所示操做便可,再也不翻譯。
private SchoolContext db = new SchoolContext();
Index
action method 從數據庫上下文獲取 Students
屬性,返回學生列表:
public ViewResult Index()
{
return View(db.Students.ToList());
}
The 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>
}
點擊Students 查看。
EF的這些慣例,使得以上所寫代碼很少:
ID
或 classnameID
做爲主鍵. 慣例能夠沒必要遵照(如本文不用複數形式做爲表名),若是使用慣例或者覆蓋慣例,請查看後面的 Creating a More Complex Data Model 。更多信息請查看. Code First Conventions.
使用 Entity Framework 和SQL Server Express 建立了一個簡單的web程序。隨後將學習如何完成基本的 CRUD (create, read, update, delete) 操做.