積跬步,為的是千里之遙!
一、ADO.NET 的存儲方式
之前我們都是通過 ADO.NET 提供的類,把我們要執行的SQL語句傳遞到底層數據庫引擎,來進行解析執行,然后獲取返回結果。
這種開發方式具有非常大的彈性,但相對也存在一定的風險。
從SQL語句的處理到數據類型的轉換都可能發生錯誤,特別是隨着系統規模的逐漸增長,這些錯誤造成的問題將越發嚴重。
二、Entity Framework 的存儲方式
Entity Framework 通過實體數據模型映射到底層的數據結構,開發人員只需編寫C#程序代碼來處理實體數據對象,
從而降低了因SQL不規范而導致的程序錯誤和安全性問題。
由於數據對象本身具有類型,因此在程序開發的過程中避免了因類型轉換可能導致錯誤的程序代碼。
三、Entity Framework 項目實現
1. 先來看看,“來自數據庫的 EF 設計器”
首先,得准備好個數據庫文件 StudentInfo.mdf,這個數據庫里就一個名為 Student 的表:
然后,創建C#控制台應用程序 MyEFProject, 並在項目中添加新建項 “ADO.NET 實體數據模型”。
ok,緊接着會彈出 添加新建項 窗口,選擇 “ADO.NET 實體數據模型”,並將其名稱更改為 “StudentInfoModel” 。
接着會這么着:
使用 EF 之后,如何對表對象進行操作呢?下圖:
這樣就可以輕輕松松的進行數據處理了!
四、實體類型和 .edmx 文件
實體數據類型是一種XML格式的純文本文件,以 .edmx 為擴展名。
.edmx 文件內容包括:存儲模型、概念模型、以及兩種模型之間的相關設置。
Visual Studio 提供了 實體數據模型設計器(ADO.NET Entity Data Model Desiger),它是一款可視化圖形工具。
雙擊項目中的 .edmx 文件,就可以打開這個工具,界面如下:
如果想查看該文件的原始文件內容,可以使用 XML編輯器 方式進行打開 .edmx 文件。
打開之后就是一個比較傳統的(traditional) XML文件:
實體模型包含三部分:
- 存儲模型(SSDL,Store Schema Definition Language,存儲結構定義語言)
- 概念模型(CSDL,Conceptual Schema Definition Language,概念模式定義語言)
- 映射 (MSL,Mapping Specification Language,映射規范語言)
1、存儲模型:
概念模型是用來存儲原始數據庫的結構信息,其結構中包含描述對象內容的元素:EntityContainer 和 EntityType 。
a、EntityContainer 元素: 表示這個區域是一個實體容器,對應特定的數據源。
<EntityContainer Name="StudentInfoModelStoreContainer"> <EntitySet Name="Student" EntityType="Self.Student" Schema="dbo" store:Type="Tables" /> </EntityContainer>
比如這里對應的是要操作的數據庫 StudentInfo.mdf,使用LINQ相關技術搜索其內容時,一個對應的 StudentInfoEntities 類型對象被返回,
應用程序可通過此對象與數據庫進行互動。
其中的 EntitySet 元素描述了實體容器中所包含的數據對象內容。
b、EntityType 元素: 表示對應相關數據內容中的實體類型 Student (如同數據表 Student 中的信息)。
實體類型元素以 <EntityType Name="Student"> 表示,表示數據模型映射的 Student 類。
而節點 <Key><PropertyRef Name="Id" /></Key> 表示數據模型的主鍵對應屬性 (如同數據表中的主鍵)。
接下來一連串的屬性配置,分別對應 Student 類中的各個屬性的特性內容:屬性名稱(Name)、屬性類型(Type)以及是否為空(Nullable)等等。
<Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
Property 元素的特性在程序執行過程中,會進一步映射到實體數據模型連接的底層數據庫,
在 EF 中被稱為facet,根據不同的數據類型,均有其特定的facet可供設置,它們描述除了數據大小之外的其他特性的額外信息。
2、存儲模型:
概念模型定義實體數據模型與類結構,然后通過存儲模型映射到底層數據源結構。
可以看出 其中內容與 概念模型 相似,不過要注意的是,它的實體類型與屬性均是來自於低層數據庫的真實名稱。
3、映射:
這個模塊負責支持存儲模型與概念模型兩個區塊的內容映射。這么一來,實體數據屬性才能映射到底層的數據源。
可以看到,映射模塊將 Student 實體的屬性名稱(Name)逐一映射到底層數據庫的 Student 數據表的字段名(ColumnName)。
我們還可以通過 實體設計器 來查看它們的映射關系:
五、實體數據模型與類文件
1、DbContext 和 DbSet
除了數據模型的內容外,我們必須要了解的兩個類:DbContext 和 DbSet 。
DbContext 類:程序通過 DbContext 的對象實例來建立與數據庫的連接,並支持數據庫的查詢與更新等相關操作。
DbSet 類:這個類主要起到映射作用,映射到特定的數據表結構,表示映射的數據表其實體數據內容的集合。
每一個實體數據模型都會建立 DbContext 類以供程序進行數據連接,並根據數據庫中的表結構逐一創建對應的DbSet類,
程序則進一步通過類的調用,在EF的環境下執行各種數據庫操作。
來看下 StudentInfoModel.Context.cs 這個文件:
StudentInfoEntities 繼承了 DbContext 類,而 Student 屬性 返回的是Student 類的 DbSet 對象,它映射的是 StudentInfoEntities 連接數據庫中的 Student 表,表示 Student 的數據集合。
在 StudentInfoModel.tt 4T 模板的節點下,可以找到定義的 Student 類。
其中的屬性逐一映射到 Student 數據表結構字段。
有了DbContext 和 DbSet 這兩個重要的類以后,我們就可以通過以下代碼來建立數據庫連接,並獲取到Student表中的數據了:
//StudentInfoEntities 繼承了 DbContext 類,因此 stuInfo 是一個 DbContext 對象,它與數據庫完成了連接操作; //通過調用 stuInfo 的 Student 屬性,即可獲取到數據庫 Student 表中的數據內容,並將其封裝成 DbSet<Student> 對象返回給 stus。 StudentInfoEntities stuInfo = new StudentInfoEntities(); DbSet<Student> stus = stuInfo.Student; //DbSet 是一組數據集,為了方便遍歷其數據,可以通過 ToList 方法將其轉換成 List 類型。 List<Student> list = stuInfo.Student.ToList(); //也可以通過 LINQ 來進行轉換 IEnumerable<Student> students = stuInfo.Student.Select(x => x);
Student 表中的每一條數據對應的封裝成一個 Student 對象,再通過 Student 對象的屬性獲取相應的數據內容。