請注明轉載地址:http://www.cnblogs.com/arhat
在前幾章中,老魏一直使用Linq來查詢Entity Framework。但是老魏感覺,如果使用Linq的話,那么Linq的返回值類型有的時候不是很容易找出來,沒有直接使用Lambda來的直觀,至少在Lambda中我們可以指定返回的類型,這樣一來就可以指定返回值了。
在本章的開始呢,老魏先復習一下.NET提供的幾個常用的Lambda委托,而這些委托可以說是經常又得到的,尤其實在IEnumerable<T>和 IQueryable<T>的擴展方法中經常的被用到。
常用委托:
1.封裝一個具有一個參數並返回 TResult 參數指定的類型值的方法。
public delegate TResult Func<in T, out TResult>(T arg)
這個委托有兩個類型參數,一個輸入參數和返回值:
in T:此委托封裝的方法的參數類型。
out TResult:此委托封裝的方法的返回值類型。
那么這個委托怎么用呢?
Func<int,int> f = a=>{return a+1;}; int b = f(1);
結果b=2
2.封裝一個具有兩個參數並返回 TResult 參數指定的類型值的方法。
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=3
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中怎么使用。希望能給大家帶來幫助!順便這里老魏說一下,發表文章的時間還是不確定,因為時間有限,所以只能在閑暇的時間來寫文章了。