在錯誤中學習ASP.NET MVC 第 28 篇 - 認識Model - LINQ to Entities 與 導覽屬性

 眼看就要進入尾聲了,今天就來講如何從資料庫撈資料吧!使用的語言就是Language-Integrated Query (LINQ),LINQ除了可以針對entity查詢之外,也可以針對object或xml來查詢,今天就直接針對LINQ to Entities來做說明,最後再補充導覽屬性的應用

LINQ to Entities

LINQ to Entities 的查詢提供兩種語法:

  1. 以方法為基礎的查詢語法(Lambda 運算式)
  2. 查詢運算式語法(看起來類似SQL語法)

1.以方法為基礎的查詢語法

使用Scaffold產生的程式碼,預設都是使用『以方法為基礎的查詢語法』方式來做CURD,直接看Code:
必須先建立DbContext才能以物件的方式查詢entity,如下圖的UserEntities1繼承DbContext



Create(新增User),使用Add()方法



Update(修改User),使用Entry()方法並搭配db.SaveChanges()方法



Read(讀取User),使用Find()方法



Delete(刪除User),使用Remove()方法並搭配db.SaveChanges()方法



而在昨天改寫Scaffold產生的程式碼以符合顯示多筆Email資訊的功能,也有使用到Where()方法,其中的d => d.UserID == id就是Lambda 運算式


在之前View裡面使用html helper時搭配For結果的方法也時常使用到Lambda 運算式,使用方式如下:

自訂義參數名稱 => 自訂義參數名稱.物件屬性

另外還有很多時常用到的方法,例如:Select()、OrderBy()、Take()與Skip()等等,在初學的時候其實都是邊開發專案邊查詢,相關的使用範例可以看這個網站101 LINQ Samples

再來看另外一種

2.查詢運算式語法

將昨天透過方法取得資料庫資料的程式碼改寫成「查詢運算式語法」,如下圖39行,跟SQL很類似都是搭配from、where或select這些關鍵字來組成查詢語法,這邊我自己剛開始學習時非常難適應,因為我DB那塊就是弱到爆炸,所以反而很喜歡透過方法查詢的方式,可以透過方法或以物件導向的觀念直接跟DbContext溝通,不過在特殊情況「查詢運算式語法」真的超級好用,例如做join五個table時我就習慣用「查詢運算式語法」,因為可以直接將SSMS(SQL Server Management Studio)產生的SQL直接改寫成linq,如果用方法或函式的方式,說真的我還不會寫勒XD



另外39行最後的ToList()的使用,是因為Where()會回傳一個IQueryable型別的物件,會將Linq組成T-SQL,當此行程式碼被執行時才會去資料庫執行query撈取資料

導覽屬性

提供三種載入模式

  1. 延遲式載入(Lazy loading):預設的載入模式,存取導覽屬性時才會去DB撈資料
  2. 積極式載入(Eager Loading):載入資料時連同關聯的資料一起載入
  3. 明確式載入(Explicit loading):嚴格控管撈取資料的時機,只有在程式要求執行時才會去撈資料

1.延遲式載入

觀察Day23專案的資料模型,可以看到一個使用者可以有多筆Email,建立關聯之後(中間的虛線),User實體下就會出現Email的導覽屬性



執行畫面如下



使用延遲式載入寫改昨天的程式碼,使用方式非常簡單,透過User物件去存取Email這個導覽屬性就能直接去資料庫取得資料,而取得資料的時機就是40行存取Email這個導覽屬性的時候,所以下圖這個Action 總共跟資料庫溝通了兩次:
第一次是31行取得User資料的時候
第二次是40行取得導覽屬性Email的時候


如果想要減少資料庫的溝通,是否可以在取得User資料時就將Email也載入呢,就是使用接下來的積極式載入

2.積極式載入

使用Include方法,並搭配SingleOrDefult回傳一筆資料,若找不到而回傳null,沒有搭配之前Find()方法是因為Find是屬於DbSet的方法無法與Include搭配。改寫如下圖32行,那麼此Action只會與資料庫連線一次就把所需要的資料通通取回來囉!而以方法為「基礎的查詢語法」與「查詢運算式語法」可以搭配使用,請參考下圖的寫法2


3.明確式載入

寫法如下圖,第一次透過資料庫取得User資料,在34行時透過Load()將導覽屬性的資料載入,這跟延遲式載入沒有什麼差別
記得先把lazyloading關閉,db.Configuration.LazyLoadingEnabled = false;,並透過Entry方法與Collection將導覽屬性載入



但如果我只想先載入兩筆資料,就可以透過明確式載入告訴資料庫要如何載入導覽屬性的資料,例如下圖34行宣告了一個IQueryable型別的變數,等到第41行才會去資料庫執行取資料的動作,如果今天Email有100筆,也只會取回2筆,但是如果透過延遲式或積極式載入可是會直接將100筆直接載回來的喔!有點浪費XD



如果想觀察linq與資料庫的連線可以使用Sql Profiler來監看linq的執行,不過這功能只有SQL Server Standard才有,我只有Express版就不示範了XD



下載今日專案:https://github.com/juben-wang/MvcApplication28


留言

這個網誌中的熱門文章

CPE 一顆星選集題目說明與解答 - Java 筆記與心得分享

Visual Studio 自動排版格式化程式碼

1. Vito's family (CPE10406, UVA10041) - CPE一顆星解答與說明