在這篇教程里,你會學習如何在ASP.NET MVC里使用微軟實體框架(Microsoft Entity Framework)。你會學習怎樣使用實體向導來創建一個ADO.NET 實體數據模型。通過這個教程的課程,我們會建立一個Web應用來說明如何通過Entity框架來選擇、插入、更新和刪除數據。
使用實體框架創建模型類(C#)
這篇教程的目的是向你解釋這你創建一個ASP.NET MVC應用的時候,你可以怎樣使用微軟實體框架來創建數據接入類。這篇課程假定你之前沒有微軟實體框架的知識。在這篇教程的末尾,你會明白怎樣使用實體框架來選擇、插入、更新和刪除數據庫記錄。
微軟實體框架(Microsoft Entity Framework)是一個對象關系映射工具(Object Relational Mapping ,O/RM)工具。它可以讓你從一個數據庫自動地生成數據接入層。實體框架免去了你手工創建數據接入層的乏味工作。
為了向你說明怎么在ASP.NET MVC里使用微軟實體框架的,我們將會創建一個簡單的應用程序。我們將創建一個Movie數據應用。它可以讓你顯示和編輯數據庫記錄。
這篇教程假定你安裝了Service Pack 1的Visual Studio 2008或者Visual Web Developer 2008。你需要Service Pack 1來使用實體框架。你可以從下面的地址安裝 Visual Studio 2008 Service Pack 1或者帶有Service Pack 1的 Visual Web Developer:
ASP.NET MVC和微軟實體框架沒有什么實質的聯系。已有幾個可以供ASP.NET MVC框架使用的實體框架。例如:你可以使用諸如Microsoft LINQ to SQL、NHibernate又或者SubSonic的其它O/RM工具創建你的MVC模型類。
創建Moive例子數據庫
Moive數據庫應用使用一個名叫Movies包含了下列欄目的數據庫表:
| 欄目名稱 |
數據類型 |
允許空? |
主鍵? |
| Id | int | False | 真 |
| Title | nvarchar(100) | False | 假 |
| Director | nvarchar(100) | False | 假 |
你可以通過下列的步驟添加這個表到ASP.NET MVC項目:
- 在解決方案瀏覽器窗口里右鍵單擊App_Data文件夾,並選擇菜單項"添加"、"新項"
- 從添加新項的對話框中,選擇SQL Server數據庫,以MoviesDB.mdf命名該數據庫,然后點擊確定按鈕
- 雙擊MoviesDB.mdf文件來打開服務器瀏覽器/數據庫瀏覽器窗口。
- 展開MoivesDB.mdf數據庫連接,右鍵單擊表文件夾,並選擇菜單項添加新表。
- 在表設計器里,添加Id、Title和Director列。
- 點擊保存按鈕(有個磁盤圖標的那個按鈕),以Movies為名字保存新表。
在你創建Movies數據庫表后,你應該添加一些簡單的數據到表里。右鍵單擊Movies表並選擇菜單項顯示表數據。你可以在出現的表里輸入假的電影數據
創建ADO.NET實體數據模型
要使用微軟實體框架,你需要創建一個實體數據模型。可以利用Visual Studio實體數據模型向導來從一個數據庫自動地生成實體數據模型。
照着下面的步驟:
- 在解決方案瀏覽器窗口里右鍵單擊Models文件夾,然后選擇菜單項添加,新項。
- 在添加新項對話框里,選擇數據類(如圖1)。
- 選擇ADO.NET實體數據模型模板,給這個實體數據模型命名為MoviesDBModel.edmx,然后點擊添加按鈕。點擊添加按鈕的時候會載入數據模型向導。
- 在選擇模型內容步驟,選擇從數據庫生成選項,然后點擊下一步按鈕(如圖2)。
- 在選擇數據連接步驟,選擇MoviesDB.mdf數據庫連接,輸入實體連接設置名字為MoviesDBEntities,然后點擊下一步按鈕(如圖3)。
- In the Choose Your Database Objects step, select the Movie database table and click the Finish button (see 圖 4).
- 在選擇數據對象中,選擇Movie數據庫表然后點擊完成按鈕(如圖4)。
在完成這寫步驟后,ADO.NET 實體數據模型設計器(實體設計器)打開了。
圖 1 --創建一個新的實體數據模型

圖 2 -- 選擇數據內容步驟

圖 3 --選擇數據連接

圖 4 - 選擇數據庫對象

修改ADO.NET實體數據模型
在創建完實體數據模型后,你可以修改通過實體設計器來修改模型(如圖5)。你可以在任何時候通過雙擊在解決方案瀏覽器里的Models 文件夾的MoviesDBModel.edmx來打開實體設計器。
圖 5 -- ADO.NET 實體數據模型設計器

例如,你可以使用實體設計器來改變實體模型數據向導生成的類的名字。向導創建了一個新的名叫Movies的數據接入類。換句話說,向導給了這個類和數據庫表一樣的名字。由於我們將會使用這個類來表示一個特定的電影實例,我們應該將Movies重命名為Movie。
如果你想重命名一個實體類,你可以雙擊實體設計器里的類的名字然后輸入一個新的名字(如圖6).或者,你可以在實體設計器里選擇一個實體后在屬性窗口里修改這個實體的名字。
圖 6 -- 改變一個實體的名字

記住在修改后保存你的實體數據模型。在這個場景后面,實體設計器生成了一系列的C#類。你可以在解決方案瀏覽器窗口里通過打開MoviesDBModel.Designer.cs文件看到這些類。
別修改Designer.cs里面的代碼,因為你的改動着下一次使用實體設計器的時候會被覆寫。如果你想要擴展在Designer.cs里面的實體類的功能,你可以中單獨的文件里創建部分類(partial classes)。
通過微軟實體框架選擇數據庫數據
讓我們從一個顯示電影記錄的列表的頁面開始我們的Movie數據應用程序開發吧。清單1的Home控制器暴露了一個名叫的Index()的行為。Index()行為通過微軟實體框架返回了所有Movie數據庫表的記錄。
清單 1 - Controllers\HomeController.cs
using System.Web.Mvc;
using MovieEntityApp.Models;
namespace MovieEntityApp.Controllers
{
[HandleError]
public class HomeController : Controller
{
MoviesDBEntities _db;
public HomeController()
{
_db = new MoviesDBEntities();
}
public ActionResult Index()
{
ViewData.Model = _db.MovieSet.ToList();
return View();
}
}
}
注意清單1的控制器包含了一個構造函數。該構造函數初始化了一個名叫_db類-級的字段。_db字段表示的是微軟實體框架生成的數據庫實體。_db字段是MoviesDBEntities類的一個實例。它由實體設計器生成。
為了使用Home控制器的MoviesDBEntites類,你必須引入MovieEntityApp.Models命名空間(MVC項目名.Models)。
_db字段中Index()行為里被使用來檢索數據庫表的記錄。_db.MovieSet語句代表了數據庫表里的所有記錄。ToList()方法被用以轉換電影的記錄集到一個泛型的Movie對象集合 (List<Movie>)。
通過LINQ to Entites的幫助,電影記錄被檢索了。清單1的Index()行為使用了LINQ方法語法來檢索數據庫記錄的集合。如果你喜歡,你可以使用LINQ查詢語法來代替。下面的兩句話完成了相同的工作:
ViewData.Model = _db.MovieSet.ToList();
ViewData.Model = (from m in _db.MovieSet select m).ToList();
使用whichever LINQ語法--函數語法或查詢語法,你覺得最直觀的那種。這兩種方法沒有什么性能上的差別--不同的只是風格。
清單2的視圖被用來顯示電影記錄。
清單 2 - Views\Home\Index.aspx
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title >Index </ title >
</ head >
< body >
< div >
<% foreach (var m in ViewData.Model)
{ %>
Title: <% = m.Title %>
< br />
Director: <% = m.Director %>
< br />
<% = Html.ActionLink( " Edit " , " Edit " , new { id = m.Id }) %>
<% = Html.ActionLink( " Delete " , " Delete " , new { id = m.Id }) %>
< hr />
<% } %>
<% = Html.ActionLink( " Add Movie " , " Add " ) %>
</ div >
</ body >
</ html >
清單2的視圖包含了一個 foreach 循環。它枚舉了每一個電影記錄並顯示了每一個電影記錄的Title和Director屬性。注意到編輯和刪除連接是顯示在每一個記錄的附近的。此外,一個添加連接在視圖的底部出現(如圖7)。
圖 7 - The Index view

Index視圖是一個類型化的視圖。Index視圖包含了一個<%@Page%>指令。該指令的Inherts屬性投射了Model屬性到一個強類型的泛型Movies對象集合(List<Movie>)。
通過微軟實體框架插入數據庫記錄
你可以使用微軟實體框架來讓插入新記錄到一個數據庫表變得很容易。清單3包含來你可以用以插入新記錄到Movie數據庫表的兩個新加入到Home控制器的行為。
清單 3 - Controllers\HomeController.cs (Add methods)
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(FormCollection form)
{
var movieToAdd = new Movie();
// Deserialize (Include white list!)
TryUpdateModel(movieToAdd, new string[] { " Title ", " Director " }, form.ToValueProvider());
// Validate
if (String.IsNullOrEmpty(movieToAdd.Title))
ModelState.AddModelError( " Title ", " Title is required! ");
if (String.IsNullOrEmpty(movieToAdd.Director))
ModelState.AddModelError( " Director ", " Director is required! ");
// If valid, save movie to database
if (ModelState.IsValid)
{
_db.AddToMovieSet(movieToAdd);
_db.SaveChanges();
return RedirectToAction( " Index ");
}
// Otherwise, reshow form
return View(movieToAdd);
}
第一個Add()行為簡單地返回了一個視圖。該視圖包含了一個添加一個新電影數據庫記錄的表單(如圖8).在提交該表單后,第二個Add()行為被調用了。
注意第二個Add()行為是被AccetpVerbs標簽裝飾的。這個行為當且僅當HTTP POST操作被執行的時候可以被調用。換句話說,這個行為只能在提交一個HTML表單的時候被調用。
第二個Add()行為中ASP.NET MVC的TryUpdateModel()幫助下創建了一個Movie類的新實例。TryUpdateModel()從傳遞到Add()函數的FormCollection里去的字段的值然后將這些HTML表單的值和Movie類的屬性一一對上。
在使用微軟實體框架的時候,在使用TryUpdateModel或UpdateModel方法來更新實體類的屬性的值的時候你必須提供一個屬性的"白名單"
接下來,Add()行為執行了一些簡單的驗證。行為驗證了標題和導演的值都有值。如果有驗證錯誤,則一個驗證錯誤消息會被添加到ModelState。
如果沒有驗證錯誤,那么一個新的電影記錄就會通過微軟實體框架的幫助添加到數據庫表。新的數據庫記錄會由下面的兩行代碼添加到數據庫里:
_db.AddToMovieSet(movieToAdd);
_db.SaveChanges();
第一行的代碼添加新的Movie實體到微軟實體框架追蹤的電影集合。第二行的代碼保存了Movies里面所有的改動到底層的數據庫。
圖 8 -- 添加視圖

使用微軟實體框架更新數據庫記錄
你可以沿着幾乎和我們剛插入新記錄到數據那樣完全一樣的方法去使用微軟實體框架來編輯一個數據庫記錄。清單4包含了兩個名叫Edit()的控制器行為。第一個Edit()行為返回了一個HTML表單來編輯一個電影記錄。第二個Edit()行為則嘗試更新數據庫。
清單 4 - Controllers\HomeController.cs (Edit methods)
{
// Get movie to update
var movieToUpdate = _db.MovieSet.First(m => m.Id == id);
ViewData.Model = movieToUpdate;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection form)
{
// Get movie to update
var id = Int32.Parse(form[ " id "]);
var movieToUpdate = _db.MovieSet.First(m => m.Id == id);
// Deserialize (Include white list!)
TryUpdateModel(movieToUpdate, new string[] { " Title ", " Director " }, form.ToValueProvider());
// Validate
if (String.IsNullOrEmpty(movieToUpdate.Title))
ModelState.AddModelError( " Title ", " Title is required! ");
if (String.IsNullOrEmpty(movieToUpdate.Director))
ModelState.AddModelError( " Director ", " Director is required! ");
// If valid, save movie to database
if (ModelState.IsValid)
{
_db.SaveChanges();
return RedirectToAction( " Index ");
}
// Otherwise, reshow form
return View(movieToUpdate);
}
第二個Edit()行為通過從數據庫檢索Id符合正在編輯的記錄的Id的電影記錄開始。下面的LINQ to Entities語句獲得了符合特定Id值的數據庫記錄:
var movieToUpdate = _db.MovieSet.First(m => m.Id == id);
接下來,TryUpdateModel()方法被用來分配HTML表單里的值到電影實體的屬性。注意到一個白名單被提供用以指定准確的要更新的屬性。
接下來,一些簡單的嚴重被執行用以驗證電影的標題和導演屬性都有值。如果有一個屬性沒有值,那么一個嚴重錯誤消息就會被添加到ModelState並且ModelState.IsValid返回一個false值。
最后,如果沒有驗證錯誤,那么底層的數據表會在調用SaveChanges()方法的時候更新所有變動。
在編輯數據庫記錄的時候,你需要傳遞記正在被編輯的記錄的Id值到執行數據更新的控制器行為。否則,控制器行為無法知道要更新底層數據庫的哪條記錄。清單5的編輯視圖,包含了一個表示正在被編輯的數據庫記錄的Id值的隱藏域。
清單 5 - Views\Home\Edit.aspx
<%
@ Page Language
=
"
C#
"
Inherits
=
"
System.Web.Mvc.ViewPage<MovieEntityApp.Models.Movie>
"
%>
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
runat
="server"
>
<
title
>Edit
</
title
>
<
style
type
="text/css"
>
.input-validation-error
{
background-color
:
Yellow
;
}
</
style
>
</
head
>
<
body
>
<
div
>
<
h1
>Edit Movie
</
h1
>
<
form
method
="post"
action
="/Home/Edit"
>
<!--
Include Hidden Id
-->
<%
=
Html.Hidden(
"
id
"
)
%>
Title:
<
br
/>
<%
=
Html.TextBox(
"
title
"
)
%>
<
br
/><
br
/>
Director:
<
br
/>
<%
=
Html.TextBox(
"
director
"
)
%>
<
br
/><
br
/>
<
input
type
="submit"
value
="Edit Movie"
/>
</
form
>
</
div
>
</
body
>
</
html
>
使用微軟實體框架來刪除數據庫記錄
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title >Edit </ title >
< style type ="text/css" >
.input-validation-error
{
background-color : Yellow ;
}
</ style >
</ head >
< body >
< div >
< h1 >Edit Movie </ h1 >
< form method ="post" action ="/Home/Edit" >
<!-- Include Hidden Id -->
<% = Html.Hidden( " id " ) %>
Title:
< br />
<% = Html.TextBox( " title " ) %>
< br />< br />
Director:
< br />
<% = Html.TextBox( " director " ) %>
< br />< br />
< input type ="submit" value ="Edit Movie" />
</ form >
</ div >
</ body >
</ html >
在這篇教程里我們需要對付的最后的數據庫操作是刪除數據庫記錄。你可以使用清單6的控制器行為來刪除一個特定的數據庫記錄。
清單 6 -- \Controllers\HomeController.cs (Delete action)
{
// Get movie to delete
var movieToDelete = _db.MovieSet.First(m => m.Id == id);
// Delete
_db.DeleteObject(movieToDelete);
_db.SaveChanges();
// Show Index view
return RedirectToAction( " Index ");
}
Delete()行為首先從Movie實體檢索符合傳入的Id的實體。接下來,該電影通過調用DeleteObject()方法和SaveChanges()方法被從數據庫中刪除。最后,用戶被重定向到Index視圖。
總結
這篇教程的目的是演示如何通過利用ASP.NET MVC和微軟實體框架的優勢來創建數據驅動的Web應用。你可以學習到如何開發一個允許你選擇、插入、更新和刪除數據庫記錄的應用。
首先,我們討論了如何用Visual Studio的實體數據模型向導來生成一個實體數據模型。接下來,你學習了如何使用LINQ to Entities來從一個數據庫表檢索一個數據庫記錄的集合。最后,我們使用了微軟實體框架來插入、更新和刪除數據庫記錄。
