本系列教程發上去以后,有的朋友問我為什么不用Code First呢?個人認為,各種方法各有千秋,而且不管用哪種模式,最后達到的效果是一樣的,實質上使用的基本方法是相通的,這就足夠了.況且前面已經全文翻譯了一本書,如果重復這本書的內容,就沒多大意思了,毫無疑問,本文對於Code First模式的學習也是有指導作用的,理解了基本的機制,再進行其他方面深入知識的掌握就容易了,不是嗎?我在這里寫的內容都是通過不斷的實踐摸索總結出來的,可以說是很基礎的東西,並不是想要炫耀什么,只是因為前面自已走的彎路太多,不想讓像我這種剛入門的人再重復一些不必要的彎路而已...
書歸正傳,接上期博客文章,繼續將數據查詢的問題學習完畢.
5)單值選擇查詢:
在SQL數據查詢里,經常會用到SELECT DISTINCT查詢,用來搜索數據中的唯一值,注意不是第一個,而是重復數據中的一個.
比如想要查詢Product表中ProductUnit(單位)的個數,就會用到單值選擇查詢.Linq提供了Distinct擴展方法,解決這一問題,如此例,代碼應為:
var result = from c in ctx.Product select c.ProductUnitId; return result.Distinct().Count();
而使用方法語法則應為:
return ctx.Product.Select(c => c.ProductUnitId).Distinct().Count();
6)多級排序:
比如按照ProductName排序完成后,還要按ProductUnitName再次進行逆序排序,最后再按ProductBigTypeName來排序,這需要使用下面的查詢語法代碼(接前述GetProductDepositoryByPrice方法里的代碼):
var result = from c in ctx.Product join d in ctx.ProductSmallType on c.ProductSmallTypeId equals d.ProductSmallTypeId join e in ctx.ProductBigType on d.ProductBigTypeId equals e.ProductBigTypeId join f in ctx.ProductUnit on c.ProductUnitId equals f.ProductUnitId where c.ProductBasePrice<=50 && c.ProductBasePrice >=49 orderby c.ProductName,f.ProductUnitName descending,e.ProductBigTypeName select new ProductDepository { ProductName = c.ProductName, ProductBigTypeName = e.ProductBigTypeName, ProductSmallTypeName = d.ProductSmallTypeName, ProductUntName = f.ProductUnitName }; return result.ToList();
使用方法語法(按前述GetProductByPrice方法里的代碼),則應寫作:
return ctx.Product.Include("ProductUnit"). Include("ProductSmallType").Include("ProductSmallType.ProductBigType") .Where(c => (c.ProductBasePrice <= 50 && c.ProductBasePrice >= 49)) .OrderBy(c=>c.ProductName ) .ThenByDescending(c=>c.ProductUnit.ProductUnitName) .ThenBy(c=>c.ProductSmallType.ProductBigType.ProductBigTypeName) .ToList();
7)Top 10的實現
只選擇前幾條數據可以使用Take方法,比如Take(10)就表示取結果的前10條.可以直接在方法語法后面加上這個擴展方法,各位園友請自行試驗,在此不再舉例.
8)實現快速分頁的關鍵方法:Skip方法,這一方法可以跳過指定的記錄條數,返回剩余的記錄,這可以應用於快速分頁,因為跳過的記錄不會進入內存,也不會占用服務器資源,這樣就可以直接顯示指定頁面的數據了,Skip方法和Take方法協同使用,可以只調用所需要的當前頁面數據,大大縮小的查詢數據的區間,分頁效率最高.這一方法使用比較簡單,就不再舉例.
9)返回結果中第一個匹配給定條件的數據,應該使用First或FirstOrDefault方法,在給定條件有數據返回時.兩個方法類似,當給定條件無數據返回時,First方法返回Null,而FirstOrDefault方法返回為默認元素(如果是字符串,返回為"",如果是數字,返回0等等),所以注意對返回結果的處理,特別是對First方法返回值的處理,不要出現引用Null值的錯誤,否則會引發異常.通常的做法是在使用前對返回值是否為Null進行判斷,要么就使用FirstOrDefault方法.
前面介紹了大部分常用的查詢功能,有了這些查詢方法,就可以在實際工作中施展拳腳了,大家多嘗試多練習,就會體會到Linq查詢的妙處.
6、刪除數據
刪除數據有兩種情況,一種是對一對多關系中的“多”進行刪除,這很容易,直接刪除就是,比如Produc表;另一種是對一對多關系中的“一”進行刪除,如果沒有設置級聯刪除,將無法直接刪除,除非已經將符合條件的“多”的部分全部刪除了,才能正常刪除與“多”相關的“一”,個人建議開啟級聯刪除功能,這樣在實際開發工作中事半功倍,否則在實際運行中出現刪除不了的錯誤,也不好進行調試。在SQL Server Management Stuido里可以很容易地實現級聯刪除功能,見下圖:
級聯設置完成后,就可以方便地進行刪除操作了。這時候,我們就不用再顧慮是否能夠正確刪除的問題了,只要查詢到了數據,就可以刪除。
想要刪除數據,首先要找到數據,這就要用到前面所學的查詢語句及工具了。
在刪除數據時要注意,如果查詢得到的是單條數據,例如使用First或FirstOrDefault方法獲取的數據,直接調用實體類的DeleteObject方法就可以了,然后再調用SaveChanges方法將所有更改進行更新。但是如果查詢得到的是數據集合,就不能像SQL語句那樣對數據進行批量刪除操作了,這時需要使用foreach循環語句遍歷所有數據,逐個調用DeleteObject方法。最后統一調用SaveChanges方法即可(從SaveChanges方法名就可以看到,這個方法是可以批量處理數據的)。
比如想要刪除ProductSmallType表中ProductBigTypeName(需要導航得到,原表中沒有這個屬性)以9結尾的所有數據,方法如下:
1)首先在Business文件夾中新建一個類,命名為DeleteData.cs;
2)在類中添加一個方法DeleteProductSmallTypeByBigTypeName(),代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using ProductEFDemo.Models; namespace ProductEFDemo.Business { public static class DeleteData { public static void DeleteProductSmallTypeByBigTypeName() { using (var ctx = new ProductsEntities()) { var result = ctx.ProductSmallType.Include("ProductBigType") .Where(c => c.ProductBigType.ProductBigTypeName.EndsWith("9")) .ToList(); foreach (var productSmallType in result) { ctx.ProductSmallType.DeleteObject(productSmallType); } ctx.SaveChanges(); } } } }
3)在Presenter文件夾中,添加一個類:DeleteObjectView.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using ProductEFDemo.Business; namespace ProductEFDemo.Presenter { public static class DeleteObjectView { public static void DeleteProductSmallTypeByBigTypeName() { Console.WriteLine("真的要全部刪除?"); string str = Console.ReadLine(); if (str.Substring(0, 1).ToLower() == "y") { try { DeleteData.DeleteProductSmallTypeByBigTypeName(); Console.WriteLine("成功刪除所有相關數據及相關關聯數據"); } catch (Exception ex) { Console.WriteLine(String.Format ("出錯,錯誤信息為:{0}",ex.Message)); } } } } }
4)在Programm.cs中的Main函數調用這一方法,結果如下:
再到數據庫的ProductSmallType表里去找相關數據,已經沒有了,記錄已經變成了90條,到Product表里去找相關數據,記錄變成了9000條,有1000條數據也被同時刪除了,盡管我們並沒有顯示地指定要刪除這些數據,但是由於設置了級聯,就將一對多中的多的部分也刪除了。
當然了,這種刪除是對數據的永久性刪除,一般來說不是一個很好的模式,萬一想反悔已經來不及了。所以大型項目通常都是設置一個數據列,標記被刪除的那一行數據為已刪除(實際上數據還在,只是不在前台里顯示了而已),這需要使用更新語句,而不是真正的刪除語句,然后以后在確定不會后悔了以后再真的將數據清空,建議園友們在實際項目中也這樣操作,算是一味后悔葯吧!
7、更新和修改數據
這是本系列的最后一部分,實現了添加,查找,刪除,下面就該實現數據的修改了。數據修改的方法與數據刪除的方法相類似,也是先要通過Linq查詢到數據,然后給查詢到數據對象的相關屬性進行賦值修改,最后再調用SaveChanges方法更新就OK了。
同樣,對於集合類數據的修改,也不能一並進行更新處理,只能通過循環對各個對象逐個進行更新處理。這一點一定要注意!
下面對ProductUnit表中的ProductName進行修改,將所有“測試”字符串替換為””,步驟如下:
1)首先還是在Business文件夾中添加一個類:UpdateData.cs:
2)然后在類中添加一個方法實現前面要實現的更新功能:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using ProductEFDemo.Models; namespace ProductEFDemo.Business { public static class UpdateData { public static void UpdateProductUnitByUnitName() { using (var ctx = new ProductsEntities()) { var result = ctx.ProductUnit.Where(c => c.ProductUnitName.Contains("測試")).ToList(); foreach (var productUnit in result) { productUnit.ProductUnitName = productUnit.ProductUnitName.Replace("測試", ""); } ctx.SaveChanges(); } } } }
3)在Presenter文件夾中添加一個類:UpdateDateView.cs。
4)在類中實現一個方法調用剛剛創建的方法:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using ProductEFDemo.Business; namespace ProductEFDemo.Presenter { public static class UpdateDateView { public static void UpdateProductUnitByUnitName() { try { Console.WriteLine("准備更新數據..."); UpdateData.UpdateProductUnitByUnitName(); Console.WriteLine("更新成功!"); } catch (System.Exception ex) { Console.WriteLine(String.Format("出錯,錯誤信息為:{0}", ex.Message)); } } } }
5)執行程序,結果如下:
到數據庫中檢索數據,
可見數據都進行了更新和修改。是不是很方便?
總結一下,想怎樣改數據都是在實體類的對象上改,對象改完以后直接SaveChanges就OK了,很簡單很方便!
8、小結:Entity Framework還有很多高級知識,如延遲加載(Lazy Load),數據庫自定義加載,並發處置等,這些還需要進一步研究和討論,但是掌握了基礎知識以后,這些新的知識就可以獲得更好的理解了,希望園友們再接再厲,深入研究EF這一ORM工具,大幅度地提高生產力!
聲明:本文系本人原創,版權歸屬作者和博客園共同所有,任何組織或個人不得隨意轉載,修改。需要轉載請與本人聯系:qouoww@163.com。