你必须知道的EF知识和经验
推薦MiniProfiler插件
工欲善其事,必先利其器。
我們使用EF和在很大程度提高了開發(fā)速度,不過隨之帶來的是很多性能低下的寫法和生成不太高效的sql。
雖然我們可以使用SQL Server Profiler來監(jiān)控執(zhí)行的sql,不過個人覺得實屬麻煩,每次需要打開、過濾、清除、關(guān)閉。
在這里強(qiáng)烈推薦一個插件MiniProfiler。實時監(jiān)控頁面請求對應(yīng)執(zhí)行的sql語句、執(zhí)行時間。簡單、方便、針對性強(qiáng)。
如圖:(具體使用和介紹請移步)
數(shù)據(jù)準(zhǔn)備
新建實體:Score(成績分?jǐn)?shù)表)、Student(學(xué)生表)、Teacher(老師表)
后面會給出demo代碼下載鏈接
foreach循環(huán)的陷進(jìn)?
1.關(guān)于延遲加載
請看上圖紅框。為什么StudentId有值,而Studet為null?因為使用code first,需要設(shè)置導(dǎo)航屬性為virtual,才會加載延遲加載數(shù)據(jù)。
2.關(guān)于在循環(huán)中訪問導(dǎo)航屬性的異常處理(接著上面,加上virtual后會報以下異常)
"已有打開的與此 Command 相關(guān)聯(lián)的 DataReader,必須首先將它關(guān)閉。"
解決方案:
- 方案1、設(shè)定ConnectionString加上MultipleActiveResultSets=true,但只適用于SQL 2005以后的版本
- 方案2、或者先讀出放置在List中
3.以上兩點僅為熱身,我們說的陷阱才剛剛開始!
然后我們點擊打開MiniProfiler工具(不要被嚇到)
解決方案:使用Include顯示連接查詢(注意:需要手動導(dǎo)入using System.Data.Entity 不然Include只能傳表名字符串)。
再看MiniProfiler的監(jiān)控(瞬間101條sql變成了1條,這其中的性能可想而知。)
AutoMapper工具
上面我們通過Include顯示的執(zhí)行表的連接查詢顯然是不錯的,但還不夠。如果我們只需要查詢數(shù)據(jù)的某些字段呢,上面查詢所有字段豈不是很浪費內(nèi)存存儲空間和應(yīng)用程序與數(shù)據(jù)庫數(shù)據(jù)傳輸帶寬。
我們可以:
對應(yīng)監(jiān)控到的sql:
我們看到生成的sql,查詢的字段少了很多。只有我們顯示列出來字段的和一個StudentId,StudentId用來連接查詢條件的。
是的,這樣的方式很不錯。可是有沒有什么更好的方案或方式呢?答案是肯定的。(不然,也不會在這里屁話了。)如果表字段非常多,我們需要使用的字段也非常多,導(dǎo)航屬性也非常多的時候,這樣的手動映射就顯得不那么好看了。那么接下來我們開始介紹使用AutoMapper來完成映射:
注意:首先需要NuGet下載AutoMapper。
我們看到上面查詢語句沒有一個個的手動映射,而映射都是獨立配置了。其中CreateMap應(yīng)該是要寫到Global.asax文件里面的。(其實也就是分離了映射部分,清晰了查詢語句。細(xì)心的同學(xué)可能注意到了,這種方式還免去了主動Include)
我們看到了生成的sql和前面有些許不同,但只生成了一條sql,并且結(jié)果也是正確的。(其實就是多了一條CASE WHEN ([Extent2].[Id] IS NOT NULL) THEN 1 END AS [C1]。看起來這條語句并沒有什么實際意義,然而這是AutoMapper生成的sql,同時我也表示不理解為什么和EF生成的不同)
這樣做的好處?
關(guān)于AutoMapper的其他一些資料:
http://www.cnblogs.com/xishuai/p/3712361.html
http://www.cnblogs.com/xishuai/p/3700052.html
http://www.cnblogs.com/farb/p/AutoMapperContent.html
聯(lián)表查詢統(tǒng)計
要求:查詢前100個學(xué)生考試類型(“模擬考試”、“正式考試”)、考試次數(shù)、語文平均分、學(xué)生姓名,且考試次數(shù)大于等于3次。(按考試類型分類統(tǒng)計)
代碼如下:
看到這樣的代碼,我第一反應(yīng)是慘了。又在循環(huán)執(zhí)行sql了。監(jiān)控如下:
其實,我們只需要稍微改動就把101條sql變成1條,如下:
馬上變1條。
我們打開查看詳細(xì)的sql語句
發(fā)現(xiàn)這僅僅只是查詢結(jié)果集合而已,其中的按考試類型來統(tǒng)計是程序拿到所有數(shù)據(jù)后在計算的(而不是在數(shù)據(jù)庫內(nèi)計算,然后直接返回結(jié)果),這樣同樣是浪費了數(shù)據(jù)庫查詢數(shù)據(jù)傳輸。
關(guān)于連接查詢分組統(tǒng)計我們可以使用SelectMany,如下:
監(jiān)控sql如下:(是不是簡潔多了呢?)
關(guān)于SelectMany資料:
http://www.cnblogs.com/lifepoem/archive/2011/11/18/2253579.html
http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html
性能提升之AsNonUnicode
監(jiān)控到的sql
我們看到EF正常情況生成的sql會在前面帶上“N”,如果我們加上DbFunctions.AsNonUnicode生成的sql是沒有“N”的,當(dāng)你發(fā)現(xiàn)帶上“N”的sql比沒有帶“N”的 sql查詢速度慢很多的時候那就知道該怎么辦。
(以前用oracle的時候帶不帶“N”查詢效率差別特別明顯,今天用sql server測試并沒有發(fā)現(xiàn)什么差別。還有我發(fā)現(xiàn)EF6會根據(jù)數(shù)據(jù)庫中是nvarchar的時候才會生成帶“N”的sql,oracle數(shù)據(jù)庫沒測試,有興趣的同學(xué)可以測試下)
性能提升之AsNoTracking
我們看生成的sql
sql是生成的一模一樣,但是執(zhí)行時間卻是4.8倍。原因僅僅只是第一條EF語句多加了一個AsNoTracking。
AsNoTracking干什么的呢?無跟蹤查詢而已,也就是說查詢出來的對象不能直接做修改。所以,我們在做數(shù)據(jù)集合查詢顯示,而又不需要對集合修改并更新到數(shù)據(jù)庫的時候,一定不要忘記加上AsNoTracking。
多字段組合排序(字符串)
要求:查詢名字里面帶有“張三”的學(xué)生,先按名字排序,再按年齡排序。
咦,不對啊。按名字排序被年齡排序覆蓋了。我們應(yīng)該用ThenBy來組合排序。
不錯不錯,正是我們想要的效果。如果你不想用ThenBy,且都是升序的話,我們也可以:
生成的sql是一樣的。與OrderBy、ThenBy對應(yīng)的降序有OrderByDescending、ThenByDescending。
看似好像很完美了。其實不然,我們大多數(shù)情況排序是動態(tài)的。比如,我們會更加前端頁面不同的操作要求不同字段的不同排序。那我們后臺應(yīng)該怎么做呢?
當(dāng)然,這樣完成是沒問題的,只要你愿意。可以這么多可能的判斷有沒有感覺非常SB?是的,我們當(dāng)然有更好的解決方案。要是OrderBy可以直接傳字符串???
解決方案:
然后上面又長又臭的代碼可以寫成:
我們看下生成的sql:
和我們想要的效果完全符合,是不是感覺美美噠!!
lamdba條件組合
要求:根據(jù)不同情況查詢,可能情況
實現(xiàn)代碼:
是不是味到了同樣的臭味。下面我們來靈活組裝Lamdba條件。
解決方案:
這段代碼我也是從網(wǎng)上偷的,具體鏈接找不到了。
然后我們的代碼可以寫成:
有沒有美美噠一點。然后我們看看生成的sql是否正確:
EF的預(yù)熱
http://www.cnblogs.com/dudu/p/entity-framework-warm-up.html
count(*)被你用壞了嗎(Any的用法)
要求:查詢是否存在名字為“張三”的學(xué)生。(你的代碼會怎樣寫呢?)
第一種?第二種?第三種?呵呵,我以前就是使用的第一種,然后有人說“你count被你用壞了”,后來我想了想了怎么就被我用壞了呢?直到對比了這三個語句的性能后我知道了。
性能之差竟有三百多倍,count確實被我用壞了。(我想,不止被我一個人用壞了吧。)
我們看到上面的Any干嘛的?官方解釋是:
我反復(fù)閱讀這個中文解釋,一直無法理解。甚至早有人也提出過同樣的疑問《實在看不懂MSDN關(guān)于 Any 的解釋》
所以我個人理解也是“確定集合中是否有元素滿足某一條件”。我們來看看any其他用法:
要求:查詢教過“張三”或“李四”的老師
實現(xiàn)代碼:
兩種方式,以前我會習(xí)慣寫第一種。當(dāng)然我們看看生成過的sql和執(zhí)行效率之后,看法改變了。
效率之差竟有近六倍。
我們再對比下count:
得出奇怪的結(jié)論:
透明標(biāo)識符
假如由于各種原因我們需要寫下面這樣邏輯的語句
我們可以寫成這樣更好
看生成的sql就知道了
第二種方式生成的sql要干凈得多,性能也更好。
EntityFramework.Extended
這里推薦下插件EntityFramework.Extended,看了下,很不錯。
最大的亮點就是可以直接批量修改、刪除,不用像EF默認(rèn)的需要先做查詢操作。
至于官方EF為什么沒有提供這樣的支持就不知道了。不過使用EntityFramework.Extended需要注意以下幾點:
http://www.cnblogs.com/GuZhenYin/p/5482288.html
自定義IQueryable擴(kuò)展方法
?最后整理下自定義的IQueryable的擴(kuò)展。
?
轉(zhuǎn)載于:https://www.cnblogs.com/AmilyWilly/p/5731756.html
總結(jié)
以上是生活随笔為你收集整理的你必须知道的EF知识和经验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web app开发技巧总结
- 下一篇: 2016/8/1