Entity Framework 是一個位於命名空間 System.Data.Entity 中的數據訪問庫。NET4 對 Entity Framework 進行了大量改進。web
當 Entity Framework 第一次在 .NET SP1 被引入的時候,開發人員對這個版本提交了大量的反饋,反映他們認爲第一個版本不完備的地方。SQL 開發團隊認真聽取了這些反饋,在 .NET4 中,解決了這些問題。正則表達式
在 EF4 中的重要改進包括:數據庫
Visual Studio 2010 還包括一個功能更加豐富的 EF 設計器和工具支持。在 VS2010 中的 EF 設計器既支持數據庫優先 (database first) 的開發風格,從一個已經存在的數據庫開始設計模型,也支持模型優先 (model first) 的開發風格,首先設計數據模型,而後經過模型來生成數據庫的架構。瀏覽器
爲了支持以設計爲中心的開發流程,EF4 還更多地支持以代碼爲中心 (code-centric) ,咱們稱爲代碼優先的開發,代碼優先的開發支持更加優美的開發流程,它容許你:服務器
EF 代碼優先的開發如今經過就能夠支持,如今剛剛發佈 4.1 的 RC 版,你能夠經過這裏下載。架構
它與 VS2010 一塊兒工做,你能夠在任何 .NET 4 的項目中使用,包括 ASP.NET Web Forms 項目和 ASP.NET MVC 項目。asp.net
前年,我編寫了一個 MVC1.0 的 教程,這個示例發佈在這裏和書中,這個教程建立一個稱爲 NerdDinner 的簡單應用,能夠幫助人們簡單地在線組織、安排和答覆晚餐。工具
NerdDinner 教程使用數據庫優先的方式進行設計。ui
下面我將演示如何經過代碼優先的方式來完成這個目標,使用 EF4來建立 NerdDinner 的模型層和數據庫架構,而後使用 ASP.NET MVC 構建一個 CRUD 的應用。
咱們將會一步一步地建立這個應用,整個項目的下載連接在文章的後面。
咱們將經過在 VS2010 中建立一個空間的 ASP.NET MVC3 應用開始,選擇 File -> New Project,使用 ASP.NET MVC2 Empty Web Application 模板。
建立完成以後的項目以下:
下一步,咱們將會定義咱們的 NerdDinner 模型,用來表示程序中使用的數據,同時也包括集成的驗證和業務規則在內的邏輯。模型是 MVC 應用的心臟。
假定咱們尚未定義數據庫,咱們徹底從頭開建立咱們的 NerdDinner 應用。
咱們不須要從數據庫開始
在代碼優先的開發流程中,咱們不須要經過建立一個數據庫或者架構開始,相反,咱們經過編寫標準的 .NET 類定義域中的對象來開始,不須要擔憂任何複雜的持久層邏輯。
NerdDinner 是一個很小的應用,咱們的數據很是簡單,咱們但願定義和存儲 "晚餐" 來表明人們將會參加的事件,咱們也但願可以定義和存儲 "答覆"(RSVP) 來表示人們的答覆。這能夠用來跟蹤參與的特定晚餐。
讓咱們建立兩個類 Dinner 和 RSVP 來表示這些內容,咱們將會經過在項目中增長新的類來完成。
上面的 Dinner 和 RSVP 模型類是簡單和從前的 CLR 對象,一般稱爲 POCO,它們不須要從任何基類派生或者實現任何接口,屬性拋出了類型是標準的 .NET 數據類型,沒有數據持久層的標籤或者代碼附加在裏面。
定義模型類不須要將它們綁定在特定的數據庫上,特定的數據庫 API 上,或者數據庫架構的實現上,這是真正強大的能力,使得咱們能夠更加靈活地進行數據訪問,容許咱們關注在應用的邏輯上而不須要擔憂持久層的實現。同時也使 得咱們能夠靈活地改變數據庫的架構或者存儲的實現,很是流暢而不須要改寫任何咱們的模型對象,或者訪問它們的代碼。
如今咱們已經定義了咱們的兩個 POCO 模型類,下面咱們建立一個類來來完成從數據庫中獲取/持久化 Dinner 和 RSVP 實例。
咱們命名這個類爲 NerdDinners。它派生自 DbContext 基類,有兩個公共的屬性,一個暴露咱們的 Dinner 對象,一個暴露咱們的 RSVP 對象。
上面用到的 DbContext 和 DbSet 類是 EF4 代碼優先庫的一部分,你須要添加對EntityFramework 程序集的引用。同時,你還須要在類文件的開始部分增長 using System.Data.Entity 命名空間的代碼。
這就是全部你須要編寫的!
上面的三個類包含項目中基本的模型和數據持久層全部須要的代碼,甚至咱們不須要配置任何額外的數據庫架構映射信息,或者運行任何的工具,也不須要編輯任何的 xml 文件,也不須要經過任何的設計器來開始使用咱們的類。
咱們不須要任何額外的代碼,也不須要建立任何 xml 文件,也不須要工具來影射咱們的模型類與數據庫,你可能想,這怎麼可能呢?
默認狀況下,EF 代碼優先支持約定優於配置的目標,你能夠經過映射約定來代替顯式的配置參數,若是須要的話,你能夠提供自定義的映射規則來覆蓋默認的映射規則,可是,若是 你使用默認的映射規則,你會發現你須要編寫的代碼真的很是少,90% 的狀況下,你不須要任何額外的代碼或者配置。
在咱們上面的例子中,NerdDinners 上下文類將會默認的映射它的 Dinners 和 RSVPs 屬性到數據庫中的 Dinners 和 RSVPs 表,在 Dinners 表中的每一行將會映射到 Dinner 類的一個對象,與此相似,RSVP s 中的每一行將會映射到 RSVP 類的一個對象,Dinner 和 RSVP 類中的屬性將會映射到 Disnners 和 RSVPs 表的列。
EF 支持的其餘的約定規則包括基於一般的命名模式自動識別主鍵和外鍵,例如 Id 或者 DinnerId 屬性將會被識別爲主鍵,EF 還支持智能地識別模型對象之間的關係,EF 團隊有一篇博文討論默認的約定規則。點擊這裏
使用咱們模型的示例
下面咱們看一下常見的使用場景。
咱們使用下面的代碼從數據庫中查詢數據。
咱們也能夠在 LINQ 中使用 Dinners 和 RSVPs 的關係,注意,下面的 where 子句過濾 RSVP 大於 0 的晚餐。
在上面的查詢中,咱們查詢至少有一個答覆的晚餐。
咱們可使用 LINQ 的 Single() 方法,經過傳遞一個 Lambda 表達式來獲取單個的 Dinner 實例。
另外,咱們也能夠經過 EF 支持的 Find() 方法來基於 ID 獲取實例。
下面的代碼演示如何建立一個新的晚餐,而後寫入數據庫中,咱們須要的就是 new 一個 Dinner 對象,設置屬性,而後增長到 NerdDinners 上下文對象的 Dinners 屬性的集合中,NerdDinner 上下文對象支持工做單元的模式,容許增長多個對象。而後,調用 SaveChanges() 方法來做爲一個簡單的原子事務操做持久化全部的修改到數據庫中。
更新對象的屬性,而後保存到數據庫中。
下面咱們在一個更加複雜的場景下使用咱們的模型。咱們使用控制器來實現發佈一個晚餐的列表,而且容許用戶增長新的項目。
在 Controller 文件夾上右鍵,選擇 Add -> Controller 菜單,將咱們的控制器命名爲 HomeController。
而後,增長 Action 方法。
Index Action 方法獲取並生成一個晚餐的列表。
Create Action 方法容許用戶增長新的晚餐,當用戶直接訪問地址 /Home/Create 的時候,系統提供一個空白的晚餐表單以供填寫。第二個 Create 方法處理 Post 請求,將晚餐保存到數據庫中,若是有驗證沒有經過,將會向用戶返回錯誤提示信息。
下一步,咱們增長兩個視圖,一個 Index ,一個 Create.
在 Action 方法上點擊右鍵,選擇 Add View 菜單,在 Add View 對話框中,咱們使用強類型的視圖,傳遞 Dinner 的 IEnumerable 列表。
而後,選擇 Add, 將會建立 Index.aspx 視圖文件,在其中增長下面的代碼,建立一個無符號的列表來顯示晚餐。
而後,增長 Create 視圖,傳遞 Dinner 對象。
而後,在其中定義表單。
如今,咱們實現了全部須要的功能,能夠顯示晚餐,而且增長項目。
咱們已經完成了咱們的代碼,如今,運行一下。
可是,數據庫呢?
咱們尚未數據庫,由於代碼優先的工做方式並不須要一個已經存在的數據庫。
可是,當咱們實際運行咱們程序的時候,咱們仍是須要一個數據庫來保存咱們的晚餐和回覆對象。咱們能夠經過下面的兩種方式之一建立數據庫。
第二種方式很是酷,咱們下面使用這種方式。
在開始以前,咱們先配置數據庫鏈接串,來講明數據庫的位置,咱們的配置以下所示:
默認狀況下,當建立一個 DbContext 類的時候,EF Code-First 庫將會尋找與類名相同的數據庫鏈接串,由於咱們的類名爲 NerdDinners ,因此,默認狀況下,將會使用名爲 NerdDinners 的數據庫鏈接串。
配合 EF Code-First 你可使用許多種不一樣的數據庫,例如 SQL Server, SQL Express,MySQL 等等。
SQL CE4 是一個輕量級的基於文件的數據庫,免費,設置簡單,能夠嵌入在 ASP.NET 應用中,它支持低費用的寄宿環境,也能夠容易地合併到 SQL Server 中。
在定義和生成模型層的階段,SQL CE 能夠快速和從新建立你的數據庫,咱們將使用 SQL CE4 來開發 NerdDinner 應用。之後,在產品發佈的時候,經過改變數據庫鏈接串,來使用 SQL Express 或者 SQL Server,不須要修改一行程序代碼。
上面的鏈接串指向 NerdDinners.sdf 文件,使用 SQL CE4 數據庫提供器,你須要安裝 SQL CE4,能夠經過獨立安裝:獨立的 SQL CE 安裝器 或者經過安裝 WebMatrix, SQL CE4 很小,只須要幾秒的時間來安裝。
重要提示:上面的鏈接串指示在 \DataDirectory\ 文件夾下建立 NerdDinners.sdf 文件,在 ASP.NET 程序中, 就是在 App_Data 文件下,默認的 Empty ASP.NET MVC Web Application 沒有建立這個目錄,你能夠經過在項目上右鍵菜單中 Add-> ASP.NET Folder -> App_Data 來建立。
EF Code-First 支持經過模型類自動建立數據庫的架構,不須要手動來完成這些操做。
若是數據庫鏈接串指向的數據庫或者文件不存在的時候,默認將會自動進行操做,你甚至不須要任何操做就能夠。
在咱們的項目中,按 F5 運行應用,你將會看到以下的界面。
經過調用 HomeController 中的 Index 方法,咱們實例化而且訪問 NerdDinners 上下文對象來獲取全部的晚餐列表,由於數據庫鏈接串指向的 NerdDinners.sdf 並不存在,EF Code-First 將會自動建立它,而後使用 NerdDinners 來建立數據庫的架構。
在 VS 的資源管理中,點擊 Show all Files 圖標,而後點擊 Refresh 按鈕就能夠看到這個數據庫文件。
下面是數據庫中的表
Dinners 表的結構以下。DinnerId 列被配置爲主鍵,並設爲標識列。
RSVP 表的結構以下,RSVPId 列爲主鍵和標識列。
還建立了一個一對多的主外鍵關聯,由於咱們的 Dinners 有一個名爲 RSVPs 的 ICollection<RSVP> 類型的屬性,在 RSVP 類中有一個 Dinner 的屬性。
點擊 Create New Dinner 連接,將會導航到 Create 頁面。
點擊 Create 按鈕,咱們新的晚餐將會被保存到數據庫中,屢次重複以後,咱們可能會看到下面的列表。
咱們繼續重構咱們的程序,EF Code-First 包含許多不錯的開發功能來協調開發數據庫。
爲模型增長新的屬性
下面咱們作一些簡單的修改,增長一個名爲 Country 的屬性。
如今,按 F5 運行程序,將會看到下面的錯誤信息。
這是由於咱們修改了 Dinner 類,如今咱們的模型對象再也不與數據表同步了,
當 EF 自動爲你建立數據庫的時候,默認狀況下,會在數據庫中增長一個 EdmMetadata 的表來跟蹤自動建立的數據庫架構。
當 EF 檢測到你的模型對象與數據庫不一致的時候就會拋出異常信息。
從新與數據庫同步咱們的模型類
有幾種方式來同步咱們的模型對和數據庫
讓咱們看一下最後一種方式。
RecreateDatabaseIfModelChanges 功能
EF Code-First 包含一個開發時的功能支持在你修改模型類以後,自動重建你的的數據庫。當啓用以後,任何的模型修改都回致使 EF 自動重建數據庫。不須要手工步驟。
在開始開發的時候,這是一個頗有用的功能,使得你自由和靈活地重構和從新組織你的模型代碼,而不須要任何手工操做來同步數據庫的架構。尤爲是與 SQL CE4 配合的時候更加好,由於這是基於文件的數據庫,能夠在幾秒以內被刪除和重建。這能夠難以置信地加速開發流程。
啓用這個功能的簡單方式就是在Global.asax 文件的 Application_Start 中增長 Database.SetInitializer() 方法的調用。
如今,咱們從新運行程序,不會看到錯誤信息,EF 已經從新建立了數據庫。
你可能注意到,從新建立的數據庫是空的,咱們丟掉了原來加入的數據。RecreateDatabaseIfModelChanges 行爲沒有合併咱們的數據,它被設計用在開發場景下,快速、自動地爲你更新數據庫。
你能夠在建立數據庫的時候播種一些數據,下面的代碼中,我建立了兩個晚餐,而後加入到數據庫中。
在 Database.Initializer() 中咱們調用這個類。
如今,任什麼時候候咱們從新建立的數據庫中,將會已經增長了兩條數據。
咱們已經建立了一個簡單的應用。
如今的問題是,咱們沒有任何的驗證規則來保證填入的數據是正確的,下面咱們解決這個問題。
使用 DataAnnotations 增長驗證規則
在 ASP.NET MVC 中,驗證規則一般基於模型,這使得能夠在單一位置維護它們。強制在任何的控制器和視圖中使用這些規則。
ASP.NET MVC2 包含使用 System.ComponetModel.DataAnnotations 庫中的驗證規則,這容許咱們使用標籤來標註驗證規則。
回到 Dinner 類定義驗證規則。
[Required] 驗證標籤標識必須提供的屬性,[StringLength] 驗證標籤標識字符串的最大長度,[RegularExpression] 標籤容許指定一個正則表達式進行驗證,這是是驗證一個電子郵件地址。
每個標籤都支持 ErrorMessages 屬性,容許指定一個驗證失敗狀況下的錯誤信息,可使硬編碼的字符串,也能夠來自資源,能夠方便地進行本地化。
最後一步咱們回到視圖模板,增長 Site.css 的連接,還有兩個腳本的連接,最後,在 form 元素呈現以前,還要增長一行調用 Html.EnableClientValidation() 的方法調用。
這些修改將會包含錯誤信息,並應用到客戶端以及服務器端的驗證上。
讓咱們再次運行程序,建立一個新的晚餐,在沒有填充任何內容的狀況下,直接點擊 Create 按鈕,如今,咱們的驗證信息將會出如今瀏覽器上。
由於啓用了客戶端驗證,因此,驗證信息實時出如今頁面上。
注意到標題長度大於 20 個字符的時候,StringLength 驗證規則生效,而 HostedBy 將經過正則表達式驗證電子郵件地址。
驗證規則同時做用於客戶端和服務器端,這使得咱們能夠簡單清楚地保護咱們的應用。