EntityFramework走马观花之CRUD(上)
對于任何一個ORM框架,CRUD都是其核心功能,可以這么說,CRUD功能實現得好壞,直接決定了此ORM框架的命運。
CRUD是英文Create、Read、Update、Delete四個單詞的縮寫,對應于漢語,就是“增、刪、改、查”四個字。再細分一下,“增、刪、改”可歸為一類,其特點是要更新數據源,而“查”則歸為另一類,它不修改原始的數據源。
我們的技術探索之旅,從“查”開始。
1 兩種查詢數據的方式
EF主要使用兩種方式查詢數據:LINQto Entities和一組針對IQueryable<T>的擴展方法。
采用LINQ方式的查詢代碼擁有很強的可讀性:
?
[csharp]?view plaincopyprint?無需加注釋,只看代碼就能很輕松地知道其功能提取保存在數據庫中的所有書的書評數量信息。
上述功能也可以使用擴展方法實現,這時需要編寫Lambda表達式:
這兩種方式沒有好壞之分,只不過使用第二種方式可能會讓別人覺得你“比較牛B”。? :-)
2 裝入相關聯的數據
大多數數據實體間都有著各種各樣的關聯,最常見的是比如一本書關聯多個書評,這是一對多的關聯。而書與書的作者之間的關系,就是多對多關聯:一個作者可以寫多本書,一本書作者也可以不止一個。
EF在數據實體間建立導航屬性實現關聯。在實際項目中,經常是得到一個(或一堆)實體對象之后,需要查詢相關聯的“另一堆”對象所封裝的信息,這就是“關聯數據的裝入”問題。
對于這個問題,EF支持三種裝入策略。
(1)當導航屬性是virtual時,EF默認使用“延遲裝入(lazy loading)”。比如書與書評的關聯定義如下:
則僅當程序中需要訪問某Book對象的Reviews屬性時,EF才向數據庫發出SQL命令裝入相關的書評數據。
(2)如果確認與某實體對象相關聯的數據是確實需要的,可以使用Include()方法通知EF這個情況,EF將告訴數據庫:“把XXX和XXX打包,一次性地發給我”:
?
[csharp]?view plaincopyprint?這種方式稱為“預先裝入(Eager Loading)”。避免了第2次訪問數據庫的需要。
(3)第三種方式稱為“顯式裝入(Explicit Loading)”,使用Load()方法實現,例如,以下代碼讓EF裝入50條書和書評信息到內存中:
[csharp]?view plaincopyprint?這些數據“就位”后,可以緩存起來備用。
我們也可以“有目的”地只提取需要的數據,請看以下代碼:
?
[csharp]?view plaincopyprint?上述代碼將只提取第一本書的所有書評。
下面對這三種模式進行一個小結:
(1)就查詢性能而言,是“預先裝入(Eager Loading)”最好,因為數據己全部裝入內存,后繼的查詢無需再訪問數據庫。其缺點是可能會占用大量的內存。
(2)如果能預知要訪問的數據項,并且當前在內存的數據對象中,只有少數對象需要查詢獲取更進一步的數據,那么使用“顯式裝入(Explicit Loading)”策略能有效地減少數據傳輸量,獲得較高的性能。
(3)當一個實體類擁有多個一對多的關聯,而且難以預知要訪問的數據項,則“延遲裝入(Lazy Loading)”又比較合適了,它僅在“需要用到時”才提取數據,能有效地減少內存占用,但可能給數據庫服務器帶來過多的數據查詢請求。
(4)當數據實體對象需要序列化時,一定要使用“預先裝入(Eager Loading)”,其原因是序列化對象時需要使用反射查詢數據實體對象的所有屬性,如果是延遲裝入(Lazy Loading)”,將會導致向數據庫發出大量的查詢請求,而且每個對象都要發出“一堆”這樣的查詢請求,絕對會讓數據庫痛苦!
3 Find方法與本地數據
DbSet有一個Local屬性很有趣,它引用當前己裝入內存的數據,注意它包括當前己從數據庫中取出或新加的但還沒有保存到數據庫中的數據,我們可把它稱為DbSet對象的“本地數據集合”。
本地數據集合的一個重要特性是:針對它發出的各種查詢不會發往數據庫。
請看以下場景:
假設我只想提取數據庫中第1本和第11本書的書評信息,以下代碼完成這一工作:
?
[csharp]?view plaincopyprint?打開SQL Server Profiler,你會發現EF先后為上述代碼生成了4條SQL命令發給數據庫。
現在修改一下代碼,使用?“顯式裝入”+ Local查詢?方式:
?
[csharp]?view plaincopyprint?查看一下SQL ServerProfiler,你會發現EF只為上述代碼生成一條SQL命令(雖然這條命令比較復雜,但畢竟只有一條)發給數據庫,后繼的查詢都是在內存中進行的,相當地快!
“本地數據集合”還有另一個值得關注的特性。
請注意DbSet.Local屬性的類型是ObservableCollection,當向DbSet中添加和移除數據時,此“本地數據集合”對象會激發CollectionChanged事件。這對于WPF桌面應用來說實在是太妙了!
你可以在WPF桌面程序中這樣干:
使用DbContext提取數據后,讓WPF數據綁定控件(比如DataGrid)通過ViewSource組件綁定到相應DbSet的Local屬性,之后就可以在窗體上進行CRUD操作,所有操作被DbContext緩存起來,當用戶點擊“保存”按鈕(或者是關閉窗體時),調用DbContext.saveChanges()方法存入數據庫。DbContext會自動跟蹤實體對象的狀態,整個過程完全是自動化的!
如果你基于.NET 4.5并使用EF 6,則可以在WPF應用中直接使用EF6新增的異步方法,比如DbContext.SaveChangesAsync(),EF會在獨立的線程中完成數據的提取、保存等工作(線程的分派工作在底層由.NET的TPL負責,程序員可以不理會它),并且在這些工作結束時,異步方法的后繼代碼將在UI線程中執行,這樣一來,多線程應用中原來比較討厭的跨線程更新UI控件的問題就不存在了,用起來實在是方便,代碼可以精簡不少!
最后一個與“本地數據集合”相關聯的話題是DbSet的Find方法,開發時記住以下這句話就行了:
使用Find方法查詢數據時,它會先在內存中找,找不到之后再到數據庫中提取。
?
有關數據查詢的技巧還有不少,本篇文章只是介紹了我覺得比較重要的知識和比較有用的一些技巧,算是拋磚引玉吧。
?下篇文章帶領大家到EF“更新數據”這個領域“尋幽探勝”。
來源:?<http://blog.csdn.net/bitfan/article/details/13001935>?
來自為知筆記(Wiz)
轉載于:https://www.cnblogs.com/liyanwei/p/d9f9b690e71b14bcaf765a92b442e8e9.html
總結
以上是生活随笔為你收集整理的EntityFramework走马观花之CRUD(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从天而降的文字,文字掉落效果
- 下一篇: MONO,原来你是水中月