在昨天我學習了LinQ的一些基礎知識和動手寫了一些LinQ to Object的例子的基礎上,對於LinQ語法和基本的要點有了一定的了解。今天繼續自己的學習,對於今天學習的LinQ to DataSet 和LinQ to Entity做自己的一些總結,一方面加深自己的理解,另一方面也能掌握LinQ技術的實現機制,對於也跟我一樣對著一方面有興趣的也可以讓大家有個初步的感性認識,也是好的。
今天主要的篇幅會講解LinQ to Entity的C#實現機制以及解決昨天我看完一小節之後的兩點疑惑,後面會花一點篇幅對LinQ to DataSet做一個介紹,那具體的LinQ入門基本上就可以已經介紹完了。
看完了整個章節總結一下LinQ to Entity的實現機制,可以粗略的用下面的圖來說明:
EntityFrameWork:是一個對象-關系的映射系統,在關系數據庫與c#源代碼環境中的對象轉換起到了至關重要的作用,沒有它的LinQ to Entity估計會找不到對象吧,哈哈哈。它可以將關系數據庫中的數據庫和數據對象全部映射到LinQ to Entity的上下文環境,分別映射為一個ObjectContext類--數據庫對象;和對應的ObjectSet對象---對應的數據庫對象(表、視圖、存儲過程),然後我們通過前面學習的LinQ表達式就可以像操作對象一樣訪問數據和進行數據操作,其原理就在於關系數據庫中的表-行-字段其實都可以映射為對象。這或許就是LinQ to Entity的精髓吧。
結合上面的詳解可以更好的理解以下的簡略框架分析圖,畫的有一點丑,能理解就成了:
【1】首先我們需要生成一個數據模型,它是我們在源代碼環境中訪問數據庫對象的前提:
Entity FrameWork依賴於數據庫數據模型來使用LinQ查詢,表中的行被轉換為行對象的實例,每一個記錄的列被轉換為行對象的屬性。數據庫的數據模型可以通過Visual Studio來自動生成,也可以通過新增數據模型文件來手動創建映射,這次的例子采用VS生成,這樣簡單不太容易出錯。
選擇【從數據庫生成】進入下面:
點擊繼續:
測試連接通過之後,點擊確定,會生成一個連接字符串。以下有個單選項一般默認選擇【是】進入下一步:
接下來這個是比較重要的一步:我們可以看到此刻自動添加幾個dll引用,同時我們看到它將數據庫中的表間關系展現的一覽無遺,所以這也是LinQ to Entity的很神奇的地方。
結合上面直觀的數據模型圖,這裡說明一下它的構架:之前系統還原,導致電腦上的Viso沒了,所以沒能用結構化的圖形做下面的說明,大家湊合著理解吧。哈哈
一個數據庫的數據模型:(1)派生對象的上下文類:也即是前面說的ObjecgContext,可以理解他就是數據庫的一個源代碼映射。
(2)實體類:也即是前面我提到的ObjectSet,就是我們剛才所選擇映射到程序的表、視圖、存儲過程的源代碼映射。
(2.1)其中實體關系跟SQL中的表關系差不多:有一對一,一對多的關系,其關聯通過上面看到的導航屬性來關聯【表外鍵】
//前端顯示客戶表中的以下字段,今天的例子都是采用系統數據庫northWind中的數據
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"> <Columns> <asp:BoundField DataField="id" HeaderText="客戶ID"/> <asp:BoundField DataField="name" HeaderText="客戶姓名"/> <asp:BoundField DataField="city" HeaderText="城市"/> <asp:BoundField DataField="country" HeaderText="國家"/> </Columns> </asp:GridView>
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Collections; using System.Linq; using System.Data.Objects;//obejctQuery實例的命名空間 namespace LinQ { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); var retRows = from customer in myTestDB.Customers where customer.Country == "USA" select new { id = customer.CustomerID,name=customer.ContactName, city = customer.City, country = customer.Country }; GridView1.DataSource = retRows; GridView1.DataBind(); //需要將查詢的結果轉換為ObjectQuery實例,才可以跟蹤輸出SQL語句 TextBox1.Text = (retRows as ObjectQuery).ToTraceString(); } } } View Code
頁面顯示效果:
轉換的SQL語句:
SELECT 1 AS [C1], [Extent1].[CustomerID] AS [CustomerID], [Extent1].[ContactName] AS [ContactName], [Extent1].[City] AS [City], [Extent1].[Country] AS [Country]FROM [dbo].[Customers] AS [Extent1]WHERE N'USA' = [Extent1].[Country] View Code
2. 關聯查詢:前端文件也需要修改,這裡就不粘貼出來了。直接看一下後端LinQ表達式。
關聯查詢可以通過兩個表達式實現:let 和 selectMany擴展方法實現,本次就let方式做演示。
let方式:
protected void Page_Load(object sender, EventArgs e) { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); var retRows = from customer in myTestDB.Customers //let方式實現,不知道是不是為了與SQL中的左外連接一致才采用let作為關鍵字 //不過用法很相似 let leftTab=from order in customer.Orders //這個像不像SQL中的子查詢和組過濾表達式,哈哈……太像了 select order where customer.Country == "USA" select new { id = customer.CustomerID,name=customer.ContactName, city = customer.City, country = customer.Country,orderCnt=leftTab.Count() }; GridView1.DataSource = retRows; GridView1.DataBind(); //需要將查詢的結果轉換為ObjectQuery實例,才可以跟蹤輸出SQL語句 TextBox1.Text = (retRows as ObjectQuery).ToTraceString(); } View Code
轉換的SQL語句:
SELECT 1 AS [C1], [Project1].[CustomerID] AS [CustomerID], [Project1].[ContactName] AS [ContactName], [Project1].[City] AS [City], [Project1].[Country] AS [Country], [Project1].[C1] AS [C2]FROM ( SELECT [Extent1].[CustomerID] AS [CustomerID], [Extent1].[ContactName] AS [ContactName], [Extent1].[City] AS [City], [Extent1].[Country] AS [Country], (SELECT COUNT(1) AS [A1] FROM [dbo].[Orders] AS [Extent2] WHERE [Extent1].[CustomerID] = [Extent2].[CustomerID]) AS [C1] FROM [dbo].[Customers] AS [Extent1] WHERE N'USA' = [Extent1].[Country]) AS [Project1] View Code
//單表插入,new實例化方法創建一條記錄並插入更新 public void insertSignlData() { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); Customer myCust = new Customer() { CustomerID="george_liyk", ContactName="小凱哥", City="武漢", Country="USA" //為了前面的數據過濾通過,可以頁面顯示 }; //提交對象數據保存執行更新 myTestDB.Customers.AddObject(myCust); } //單表插入:Creat[T]調用每個表對象的構造函數創建一條記錄並插入更新 public void insertSignlData() { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); Customer mycust = Customer.CreateCustomer("george", "無涯子"); mycust.City = "北京"; mycust.Country = "USA"; //提交對象數據保存執行更新 myTestDB.Customers.AddObject(mycust); } View Code
關聯表對象數據插入也有兩個方法實現:一個是同事實例化兩個表對象的的相關字段值(同上面的單表做多次插入而已),一個是在實例化一個表對象的同時,對它的導航屬性頁初始化。下面的代碼演示的是第二種方式。
//關聯表數據同時插入方式- public void insertRelatData() { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); Customer myCust = new Customer() { CustomerID = "lio", ContactName = "關聯表多表插入", City = "武漢", Country = "USA", //為了前面的數據過濾通過,可以頁面顯示 Orders={ new Order{ CustomerID="lio" //由於order表中id未必填項,其余的字段這裡就不多余例舉了 } } }; //提交對象數據保存執行更新 myTestDB.Customers.AddObject(myCust); } View Code
4.表更新:
//將剛才插入的客戶名【無涯子】改為【哈哈哈】 public void updateData() { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); Customer data = (from customer in myTestDB.Customers where customer.CustomerID == "george" select customer).Single(); data.ContactName="哈哈哈"; //提交數據更新 myTestDB.SaveChanges(); } View Code
5.表刪除:
//刪除george記錄 public void deletData() { //實例化數據庫對象ObjectContext NorthwindEntities myTestDB = new NorthwindEntities(); Customer george = (from cust in myTestDB.Customers where cust.CustomerID == "george" select cust).Single(); //內存對象中刪除記錄 myTestDB.Customers.DeleteObject(george); //將此時的更新數據從內存提交數據庫更新 myTestDB.SaveChanges(); } View Code
後續:上面的頁面展示由於圖片要截圖很耽擱時間,所以就沒有一一截圖了,也可以理解,本次的內容都還沒寫完。。。。
明天後續會將剩余的內容補上。昨天太晚今天得早睡。。。
【下期內容】:LinQ to Entity的並發管理
LinQ to DataSet實現
相關的EntityDataSourse控件介紹