在前幾章中,老魏一直使用Linq來查詢Entity Framework。可是老魏感受,若是使用Linq的話,那麼Linq的返回值類型有的時候不是很容易找出來,沒有直接使用Lambda來的直觀,至少在Lambda中咱們能夠指定返回的類型,這樣一來就能夠指定返回值了。express
在本章的開始呢,老魏先複習一下.NET提供的幾個經常使用的Lambda委託,而這些委託能夠說是常常又獲得的,尤爲實在IEnumerable<T>和 IQueryable<T>的擴展方法中常常的被用到。函數
經常使用委託:測試
1.封裝一個具備一個參數並返回 TResult 參數指定的類型值的方法。優化
public delegate TResult Func<in T, out TResult>(T arg)
這個委託有兩個類型參數,一個輸入參數和返回值:
in T:此委託封裝的方法的參數類型。
out TResult:此委託封裝的方法的返回值類型。
那麼這個委託怎麼用呢? this
Func<int,int> f = a=>{return a+1;}; int b = f(1);
結果b=2spa
2.封裝一個具備兩個參數並返回 TResult 參數指定的類型值的方法。code
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1,T2 arg2)
這個委託有3個類型參數,兩個輸入參數和返回值:
in T1:此委託封裝的方法的第一個參數類型。
in T2:此委託封裝的方法的第二個參數類型。
out TResult:此委託封裝的方法的返回值類型
那麼這個委託怎麼用呢? 對象
Func<int,int,int> f = (a,b)=>{return a+b;} int b = f(1,2);
結果b=3blog
Func<int,int,bool> f1 = (a,b)=>{ if(a==b){ return true; }else{ return false; } }; bool b = f1(1,2);
結果:b=false繼承
有了這兩個委託後,下面就能夠來研究一下IQueryable< T> 接口的擴展方法了,這些擴展方法基本上就是圍繞着這兩個委託來進行的。
首先咱們來看看Where的擴展方法,這個擴展方被重載了四次,可是因爲在Ling To Entity中,有二個重載方法不被支持,因此這裏就不在對這二個重載函數進行講解了。
從圖上能夠看到有四個重載方法,可是對於類型是Expression參數類型的是專門針對Entity Framework的,因此對與沒有Expression參數的方法是從IEnumerable<T>中繼承過來的。而對於Func<TSource,Int32,Boolean>類型參數的方法是不被Entity Framework支持的。
下面咱們主要來看看這個方法:
public static IQueryable<TSource> Where<TSource>( this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate )
類型參數
TSource
source 中的元素的類型。
參數
source
類型: System.Linq.IQueryable<TSource>
要篩選的 IQueryable<T>。
predicate
類型: System.Linq.Expressions.Expression<Func<TSource, Boolean>>
用於測試每一個元素是否知足條件的函數。
返回值
類型: System.Linq.IQueryable<TSource>
一個 IQueryable<T>,包含知足由predicate 指定的條件的輸入序列中的元素。
須要注意的是凡是實現IQueryable<T>的類基本上都是一個集合類,因此這個參數是判斷集合中的每一個元素是否知足條件的,因此這個委託的輸入參數類型是TSource就是集和中的元素類型,若是這個元素知足條件,則返回一個bool值。
Demo:
List<string> list = new List<string>{「aa」,」bb」,」cccc」,」ff」}; IQueryable<string> query=list.Where<string>(a=>a.Length>3);
當list調用where方法的時候,因爲list中存放的元素類型是string因此where的輸類型參數也是string,而後看一下輸入參數Func<string,bool>,這個委託是用於判斷list集合中每一個元素的表達式,當知足條件的時候會把這個元素放入一個臨時集合中,一直到吧list中全部元素都判斷完畢以後,那麼臨時集合中存放的就是知足條件的元素,而後把這臨時的集合返回出去賦值給IEnumrable<string>
下面咱們來模擬一下這個where方法的原理:
where<string>(Expresssion<Func<TSource, bool>> predicate) { IQueryable<string> result = new List<string>(); foreach(string str in this) { if(predicate(str)) { list.Add(str); } } return result; }
當把predicate = a=>{return a.Length>3;}傳遞給這個函數的時候,在函數的if語句中就會循環的判斷這個集合中的元素,把知足的元素添加到臨時的list中,最後返回。
下面咱們來看看Select方法:
從圖上能夠看出,這個方法也是重載了4次,齊總Expression是針對Entity Framework的,可是參數Func<TSourse,Int32,TResult>是不被支持的。看到這裏的時候,咱們會很是的鬱悶,Where方法和Select方法都有一個Expression參數的方法,可是Expression是什麼,和沒有Expression的方法有什麼區別嗎?其實這是微軟對Entity Framework作的一個優化,Expression是「表達式樹」,經過Expression能夠吧表達式嵌入到SQL語句中造成一個優化的SQL,而沒有Expression的方法,不會生成優化的SQL語句,在網上你們能夠看看Func<TSource,TResult>陷阱的文章。因此呢,這裏咱們推薦使用的是Expression類型的表達式樹。
public static IQueryable<TResult> Select<TSource, TResult>( this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector )
TSource
source 中的元素的類型。
TResult
由 selector 表示的函數返回的值類型。
參數
source
類型: System.Linq. IQueryable< TSource>
一個要投影的值序列。
selector
類型: System.Linq.Expressions. Expression< Func< TSource, TResult> >
要應用於每一個元素的投影函數。
返回值
類型: System.Linq. IQueryable< TResult>
一個 IQueryable< T> ,其元素爲對source 的每一個元素調用投影函數的結果。
List<Student> list = new List<Student>() { new Student(){SId=1,SName="濟公",SAge=56,SSex="男",CId=1}, new Student(){SId=2,SName="飛龍僧",SAge=25,SSex="男",CId=2}, new Student(){SId=3,SName="劉太真",SAge=34,SSex="男",CId=2}, new Student(){SId=4,SName="玉面仙姑",SAge=78,SSex="女",CId=1}, new Student(){SId=5,SName="東方太悅",SAge=90,SSex="男",CId=3}, new Student(){SId=6,SName="無語老祖",SAge=123,SSex="男",CId=3}, new Student(){SId=7,SName="黃淑女",SAge=23,SSex="女",CId=2} }; IQueryable<string> query = list.Select<Student, string>(student => student.SName); foreach (string name in query) { Console.WriteLine(name); }
在使用select方法的時候,指定了集合中的元素類型和返回值中的元素類型。其中要查詢的集合元素類型爲Student,而返回值的類型是string。所在在lambda中咱們指定返回student.SName類型。
固然了,咱們還能夠指定多個列。代碼以下:
IQueryable<List<string>> query = list.Select<Student, List<string>>(student => { return new List<string> { student.SName, student.SAge + "" }; }); foreach (List<string> row in query) { Console.WriteLine(row[0] + " " + row[1]); }
在這個方法中,咱們指定了返回的類型是List<string>。因此在Lambda中咱們建立了一個List<string>對象,用於保存每一個元素的SName,SAge兩個屬性。這裏須要注意的是在List<student>中的每一個元素的SName,SAge都是一個List<string>。
本章就寫到這裏吧,本章之講解了Where和Select兩個擴展方法,東西很少,可是對於那些還停留在入門的朋友來講,能夠做爲參考文章。那麼在接下來的文章中,老魏還會繼續探討一下這些經常使用的擴展方法,並經過實例來顯示這些方法在Entity Framework中怎麼使用。但願能給你們帶來幫助!順便這裏老魏說一下,發表文章的時間仍是不肯定,由於時間有限,因此只能在閒暇的時間來寫文章了。