寫在前面
系列文章
延遲加載
總結
上篇文章介紹了linq中常見的幾個關鍵字,並列舉了幾個例子,算是對linq如何使用有了初步了解。上篇文章中也提到了,能夠使用linq的場合有一個要求:實現IEnumerable<T>泛型接口,或者類型兼容(可以通過Cast方法轉換,比如ArrayList)。
Linq之Lambda表達式初步認識
Linq之Lambda進階
Linq之隱式類型、自動屬性、初始化器、匿名類
Linq之擴展方法
Linq之Expression初見
Linq之Expression進階
Linq之Expression高級篇(常用表達式類型)
Linq之常見關鍵字
延遲加載在很多orm框架中都有支持,什麼是延遲加載?通俗一點,就是你需要的時候再去查詢,不需要的時候就不查詢。
Linq查詢的執行結果是IEnumerable<T>類型,而對IEnumerable<T>,在內部,C#通過yield關鍵字實現迭代器達到延遲加載的目的。從而使Linq查詢只是在需要的時候才會被執行。
下面看一個例子
1 namespace Wolfy.LinqLazyLoad 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 List<Person> persons = new List<Person>() { 8 new Person(){ ID=1,Name="wolfy1", Age=1}, 9 new Person(){ ID=2,Name="wolfy2", Age=2}, 10 new Person(){ ID=3,Name="wolfy3", Age=3}, 11 new Person(){ ID=4,Name="wolfy4", Age=4}, 12 new Person(){ ID=5,Name="wolfy5", Age=5}, 13 new Person(){ ID=6,Name="wolfy6", Age=6} 14 }; 15 //這裡使用linq進行查詢 16 var query = from p in persons 17 .OrderByDescending(p => p.Age) 18 select new { p.ID, p.Name, p.Age }; 19 //如果是linq是延遲加載的,則輸出的結果就應該是修改後的(延遲加載,說明query中此時並沒有實際加載數據) 20 //如果linq立即加載的,則此時query中就相當於一個臨時的緩沖區,數據已經存在了query中,就算對persons中某一項修改並不影響query中的數據。 21 persons[2] = new Person() { ID = 7, Name = "zhangsan", Age = 7 }; 22 foreach (var item in query) 23 { 24 Console.WriteLine(item.ToString()); 25 } 26 Console.Read(); 27 } 28 } 29 class Person 30 { 31 public int ID { set; get; } 32 public string Name { set; get; } 33 public int Age { set; get; } 34 public override string ToString() 35 { 36 return ID + " " + Name + " " + Age; 37 } 38 } 39 }
例子很簡單,通過linq查詢,按年齡降序輸出。
看一下輸出結果
通過這點也許你可能還不是很清楚。
那麼我們再舉一個linq立即加載的例子,對比一下
1 static void Main(string[] args) 2 { 3 List<Person> persons = new List<Person>() { 4 new Person(){ ID=1,Name="wolfy1", Age=1}, 5 new Person(){ ID=2,Name="wolfy2", Age=2}, 6 new Person(){ ID=3,Name="wolfy3", Age=3}, 7 new Person(){ ID=4,Name="wolfy4", Age=4}, 8 new Person(){ ID=5,Name="wolfy5", Age=5}, 9 new Person(){ ID=6,Name="wolfy6", Age=6} 10 }; 11 //使用聚合函數年齡總和 12 var result = (from p in persons 13 select p.Age) 14 .Sum(); 15 //如果是linq是延遲加載的,則輸出的結果就應該是修改後的(延遲加載,說明query中此時並沒有實際加載數據) 16 //如果linq立即加載的,則此時query中就相當於一個臨時的緩沖區,數據已經存在了query中,就算對persons中某一項修改並不影響query中的數據。 17 persons[2] = new Person() { ID = 7, Name = "zhangsan", Age = 7 }; 18 Console.WriteLine("Sum " + result); 19 Console.Read(); 20 }
輸出結果
21=1+2+3+4+5+6。這裡也說明一個問題,在linq中,一些聚合函數例如Sum,求平均值等操作會影響linq的延遲加載特性。
上面的第一個例子是延遲加載,在query中並沒有加載數據,然後你修改了persons[2]的值,你再輸出query中的每一個值的時候,此時才是真正的加載數據,而此時加載數據,persons[2]的值已經發生變化了,所以會輸出最新的persons[2]。
第二個例子中,聚合函數為什麼會影響延遲加載特性呢,其實也很好理解,比如在該例子中進行求和運算,求和運算就需要所有的值,所以就需要先將值查詢出來,然後才能求和,此時已經將結果保存在了result中,就算你下面再修改persons[2]的值,也沒有用了。
1、linq中有延遲加載的特性。
2、linq中使用聚合函數,延遲加載的特性將失效。
上面的例子,有點繞,各種緣由,需慢慢體會。
思考:為什麼yield關鍵字就能實現延遲加載的特性呢?(查找很多資料,未果)
參考文章
http://kb.cnblogs.com/page/100043/