使用linq的ToArray() ToList() ToDictionary()
當(dāng)我們對(duì)某個(gè)Ienumerable<T>對(duì)象下達(dá)where等條件式時(shí),所取得的結(jié)果會(huì)是一個(gè)實(shí)現(xiàn)了Ienumerable<T>接口的對(duì)象,此時(shí)所有指定的條件式都尚未執(zhí)行比對(duì)的操作,而只是的到了一個(gè)WhereIterator對(duì)象,拿到了由編譯器對(duì)linq expression 進(jìn)行分析之后所建立的delegate 和string。當(dāng)通過(guò)此Ienumerable<T>對(duì)象獲得Enumerator對(duì)象,并調(diào)用MoveNext函數(shù)時(shí)(foreach會(huì)觸發(fā)該函數(shù)),where Iterator開始起作用,該對(duì)象才會(huì)一筆一筆地對(duì)元素進(jìn)行條件比對(duì)。這一模式不僅用于LINQ TO Objects, 同時(shí)也用于LINQ To XML, LINQ ToDataSet 乃至LINQ To SQL, LINQ TO Entities。
但ToArray()等函數(shù)會(huì)以foreach一一巡覽Ieunmerable<T>對(duì)象中的所有元素并進(jìn)行比較,然后將符合條件的元素方放在Array中返回。
那么,操作這樣一個(gè)比較過(guò)的Array 或者 List 對(duì)象,顯然比直接操作必須在取得元素前進(jìn)行比對(duì)條件的對(duì)象集來(lái)的有效率
LINQ Expression無(wú)法完全取代函數(shù)調(diào)用。以Where為例。當(dāng)使用函數(shù)時(shí),我們可以寫下很復(fù)雜的Lambda Exression
Var pq = new[]{"ybwang", "dingmeng", "yhzhou"}
Var p5 = p1.Where(
x=>{
Bool result = false;
sqlConnection conn = new SqlConnection("…...");
Conn.Open();
Return result;
}
)
這是無(wú)法以單純的LINQ Expression 辦到的,如果硬要以LINQ Expression 來(lái)完成,就必須使用靜態(tài)函數(shù)或者是Extension Method 才行。所以學(xué)會(huì)如何調(diào)用Extension Method 以及運(yùn)用 Lambda Expression, 是活用Linq to Object 的不二法門。
c#3.0只是單純地把LINQ Expression 轉(zhuǎn)成object.Select(),
如果你自己打造了一個(gè)類Persons<T>,
Public class Persons<T>{
Private List<T> _list = new List<t>();
Public T this[int index]
{
Get{
Return _list[index];
}
}
Public void add[T item]{
_list.Add(item);
}
}
你用from o in Persons1 select o 的時(shí)候,由于這個(gè)類沒(méi)有實(shí)現(xiàn)Ienumerable<T>接口,則它將該Lambda表達(dá)式轉(zhuǎn)換為Select()方法之后,會(huì)因?yàn)檎也坏竭@個(gè)方法而報(bào)錯(cuò)。于是你得自己寫個(gè)Extension方法,示例如下
public static class PersonsExtension{
public static Persons<TResult> Select<TSource, TResult>(this Persons<TSource>, Func<TSource, TResult> selector){
//select elements using the Fucn
//return result;
}
}
可見(jiàn),選擇過(guò)程的控制權(quán)在我們手上
Linq to sql 查詢返回的那個(gè)東西,代表這一組sql語(yǔ)句,也就是說(shuō)你寫下var result = from …..的時(shí)候并沒(méi)有去數(shù)據(jù)庫(kù)進(jìn)行查詢,當(dāng)你真正用到數(shù)據(jù)時(shí),比如對(duì)result進(jìn)行foreach時(shí),才會(huì)用result里頭的sql語(yǔ)句去數(shù)據(jù)庫(kù)進(jìn)行查詢,查詢過(guò)程 默認(rèn)使用的是連接模式,即用sqlDataReader來(lái)讀數(shù)據(jù)。
示例一
aDataContext c = new aDataContext();
var result1 = from c1 in c.Customers select c1;
var result2 = from c2 in c.Customers select c2;
foreach(var item in result1){
foreach(var item2 in result2){
//do something
}
}
這是可以的,由于result1和result2屬于同一個(gè)context,當(dāng)result2開始去嘗試連接數(shù)據(jù)庫(kù)時(shí),result1會(huì)把它要的數(shù)據(jù)全部提取出來(lái),緩存到一個(gè)DataTable中,然后綁定到該DataTable,好讓result2綁定到數(shù)據(jù)庫(kù)
實(shí)例二
aDataContext c1 = new aDataContext();
aDataContext c2 = new aDataContext();
var result1 = from c1 in c1.Customers select c1;
var result2 = from c2 in c2.Customers select c2;
foreach(var item in result1){
foreach(var item2 in result2){
//do something
}
}
就不行了,因?yàn)檫@種緩存機(jī)制之適應(yīng)于同一個(gè)dataContext的不同result
有些適用于Linq to Object 的語(yǔ)法,并不適用于Linq to SQL
示例
static void main(string [] args){
var list = new [] {"A", "B", "C"};
var result = from s1 in list where CheckMe(s1) select s1;
foreach(var item in result){}
}
static bool CheckMe(string item){
return true;
}
這是可以的,但在Linq to SQL中
static void main(string [] args){
aDataContext context = new aDataContext();
var result = from s1 in context.Customers where CheckMe(s1) select s1;
foreach(var item in result){}
}
static bool CheckMe(string item){
return true;
}
這是不行的,因?yàn)閘inq不知道該如何將CheckMe函數(shù)轉(zhuǎn)化成sql語(yǔ)句。
這種情況,你可已先調(diào)用ToArray或者ToList函數(shù),使得取回的對(duì)象變?yōu)橐话愕腃ollection,于是就進(jìn)入了Linq to Object 的范圍,可以用Linq to Object 來(lái)操作它了。
在LINQ TO SQL 默認(rèn)模式中,調(diào)用submitChanges函數(shù)更新數(shù)據(jù)之前會(huì)激活一個(gè)Transaction,若期間發(fā)生任何錯(cuò)誤時(shí)會(huì)拋出一個(gè)異常,終止更新操作并調(diào)用Transcation的RollBack函數(shù)來(lái)恢復(fù)事務(wù)前的狀態(tài)。
Linq to sql 為Entity Class的每個(gè)屬性提供了Delay Load 屬性,當(dāng)該屬性的Delay Load被設(shè)置為True時(shí),Linq to SQL于擷取時(shí)便不會(huì)擷取該字段,而是等到該屬性第一次被訪問(wèn)時(shí)才下達(dá)一個(gè)SQL指令由數(shù)據(jù)庫(kù)擷取該字段數(shù)據(jù)。往往將一些二進(jìn)制data的 Delay Load設(shè)置成true
在lts(Linq To SQL)中使用select new 時(shí),所select 出來(lái)的對(duì)象是只讀的。這些對(duì)象和數(shù)據(jù)庫(kù)里邊的行并沒(méi)有什么聯(lián)系,不像是直接選出來(lái)的那些Entity Object, 你修改他們?cè)僬{(diào)用context.Submit(),就會(huì)將修改提交到數(shù)據(jù)庫(kù)
class Program{
static void Main(string[] args){
test();
}
static test(){
aDataContext context = new aDataConetxt();
var result = context.ExecuteQuery<OrdersWithTotal>("select orderId, sum(UnitPrice * Quantity) as Totla from [Order Details] group by orderId");
foreach(var item in result){
Console.WriteLine("Order Id: {0} Total : {1}", item.OrderId, item.Total);
}
}
}
public class OrdersWithTotal{
public int OrderId{get; set}
public Decimal Total{get; set}
}
當(dāng) Linq to Sql 無(wú)法滿足要求時(shí),可以用ExecuteQuery函數(shù)來(lái)直接執(zhí)行SQL指令。它需要一個(gè)類型參數(shù),該函數(shù)為每一行創(chuàng)建指定類型的對(duì)象,此處就是OrderWithTotal.然后將相同名字的字段值填入同名的屬性。這也是為何查詢語(yǔ)句里會(huì)出現(xiàn)as Total 的緣故。as Total ,則生成的OrdersWithTotal對(duì)象的Total屬性會(huì)是空的。
DataContext有一個(gè)Translate<T>(IDataReader)函數(shù),用于從實(shí)現(xiàn)了IDataReader的對(duì)象中獲取實(shí)體對(duì)象
相比于ExecuteQuery(), Translate()是架構(gòu)與IDataReader之上,所以我們可以通過(guò)ODBC、OLEDB、Oracle等ADO.Net Provider將取得的IDataReader對(duì)象轉(zhuǎn)成Entity Objects,對(duì)于轉(zhuǎn)文件、匯入等功能來(lái)說(shuō),Translate函數(shù)相當(dāng)好用。
但它有個(gè)限制,就是只能對(duì)返回對(duì)象做一次foreach,不過(guò)我們?nèi)匀豢梢酝ㄟ^(guò)ToList來(lái)跨越此限制
另外,該函數(shù)執(zhí)行之后,所取得的Entity Object 會(huì)被加入到DataContext中,受dataContext所管轄,因此你可以對(duì)這些對(duì)象做修改,然后調(diào)用dataContext.Submit將改后的數(shù)據(jù)寫回?cái)?shù)據(jù)庫(kù)