APS.NET MVC + EF (01)---Linq和Lambda表達式


1.1 Linq介紹

LINQ全稱 Language Integrated Query(語言集成查詢)。為我們提供一種統一的方式來查詢和操作各種數據。

   

  • LINQ to Object:是針對實現了IEnumerable<T>的對象的LINQ;
  • LINQ to SQL:是針對關系數據庫的LINQ;
  • LINQ to XML:是針對XML文檔的LINQ。

       

LINQ除了提供一個統一的API來操作各種數據,並且為我們提供了編譯時類型檢查和動態創建查詢表達式的能力。

   

LINQ查詢時有兩種語法可供選擇:查詢表達式語法(Query Expression)和方法語法(Fluent Syntax)。這兩種方法是互補的。

   

1.1.1 查詢表達式語法

基本語法:

from 變量 in 數據源對象

[where 條件]

[group 變量 by 表達式 into 臨時標識符]

[orderby 表達式]

select 選擇列

示例1:

static void Main(string[] args)

{

int[] nums = { 10, 15, 20, 25, 30 };

// 從數組中查詢所有偶數

var result = from n in nums

where n % 2 == 0

select n;

// 輸出查詢結果

foreach(int num in result)

{

Console.WriteLine(num);

}

}

說明:

1、查詢表達式語法與SQL(結構查詢語言)語法相同。

2、查詢語法必須以from子句開頭,可以以SelectGroupBy子句結束 

3、使用各種其他操作,如過濾,連接,分組,排序運算符以構造所需的結果。

4、隱式類型變量 - var可以用於保存LINQ查詢的結果。

   

1.1.2 方法語法

方法語法(也稱為流利語法)主要利用System.Linq.Enumerable類中定義的擴展方法和Lambda表達式方式進行查詢。

例如示例1中的查詢可以由以下方式代替,運行結果一致。

var result = nums.Where(n => n % 2 == 0);

   

關於Lambda表達式的語法,我們在后面的內容中進行詳細講解。

   

1.1.3 查詢表達式語法VS方法語法

查詢表達式語法與方法語法存在着緊密的關系

1、CLR本身並不理解查詢表達式語法,它只理解方法語法。

2、編譯器負責在編譯時將查詢表達式語法翻譯為方法語法。

3、大部分方法語法都有對應的查詢表達式語法形式:如Select()對應select、OrderBy()對應orderby

4、部分查詢方法目前在C#中還沒有對應的查詢語句:如Count()和Max()

1.2 Linq之查詢語法

1.2.1 排序

用where子句找到感興趣的數據后,Linq還可以方便的對得到的數據執行進一步處理,例如,給結果重新排序。下面的示例將以字母順序給上一個查詢的結果排序

示例2

static void Main(string[] args)

{

string[] names = { "alonso", "zheng", "smith", "jones", "smythe", "small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "singh" };

var result = from n in names where n.StartsWith("s") orderby n select n;

Console.WriteLine("s開頭的名字為:");

foreach (var item in result)

{

Console.WriteLine(item);

}

}

示例說明:

  • 這個程序與示例1幾乎相同,只是在查詢子句中增加了一行代碼:

orderby n

即實現了對結果的排序功能。與where子句一樣,orderby子句是可選的。

  • Orderby子句默認為升序,但可以添加descending關鍵字,指定降序排列。如:

orderby n descending;

  • 可以按照任意表達式進行排序,而無需重新編寫查詢。例如,要按照姓名中的最后一個字母順序排序,只需添加如下子句:

orderby n.Substring(n.Length-1);

   

1.2.2 合計運算符

運算符

說明

Count()

結果的個數

Min()

結果中的最小值

Max()

結果中的最大值

Average()

數字結果的平均值

Sum()

所有數字結果的和

示例3

class Program

{

static void Main(string[] args)

{

int[] numbers = CreateNumbers(12345);

var result = from n in numbers where n > 1000 select n;

Console.WriteLine("大於1000的個數為:" + result.Count());

Console.WriteLine("大於1000的最大數為:" + result.Max());

Console.WriteLine("大於1000的最小數為:" + result.Min());

Console.WriteLine("大於1000的平均數為:" + result.Average());

Console.WriteLine("大於1000的數的和為:" + result.Sum(n=>(long)n));

}

   

private static int[] CreateNumbers(int count)

{

Random rand = new Random(0);

int[] result = new int[count];

for (int i = 0; i < count; i++)

{

result[i] = rand.Next();

}

return result;

}

}

示例說明:

示例3中的Sum()方法傳入了一個Lambda表達式n=>(long)n,以獲得所有數字的和。這是Sum()方法的一個重載。由於和的結果太大,若個只是用Sum()會產生溢出。

   

1.2.3 查詢復雜對象

示例4

// Student

class Student

{

public int ID { get; set; }

public string Name { get; set; }

public string Sex { get; set; }

public int Age{ get; set; }

public int Class { get; set; }

   

public override string ToString()

{

return "ID:" + ID + "\tName:" + Name + "\tSex:" + Sex + "\tAge:" + Age + "\tClass:" + Class;

}

}

//main 方法

static void Main(string[] args)

{

List<Student> list = new List<Student>{

new Student{ID=1,Name="zhangsan",Sex="", Age=18,Class=50},

new Student{ID=2,Name="lisi",Sex="", Age=18,Class=50},

new Student{ID=3,Name="wuangwu",Sex="", Age=20,Class=51},

new Student{ID=4,Name="zhaoliu",Sex="", Age=20,Class=52},

new Student{ID=5,Name="zhouqi",Sex="", Age=21,Class=52},

new Student{ID=6,Name="wangba",Sex="", Age=20,Class=52}

};

var result = from stu in list where stu.Age == 18 select stu;

Console.WriteLine("年齡為18的學員為:");

foreach (var stu in result)

{

Console.WriteLine(stu);

}

}

   

1.2.4 投射:在查詢中創建新對象

投射是在Linq查詢中從其它數據類型中創建新數據類型的技術術語。Select關鍵字是投射運算符。

如Sql數據查詢語言,select用來從數據表中選擇適當的字段,在Linq中select與其類似。例如將示例4中的代碼改為如下:

var result=from stu in list where stu.Age=18 select stu.Name;

甚至可以通過給select添加表達式,來轉換查詢中的數據。如:

select stu.Name.ToUpper();

但是與sql不同,Linq不允許在select子句中有多個字段,即select stu.Name,stu.Age這樣的形式將產生一個錯誤。如果要實現上述情況,需要在select子句中創建一個新對象,來保存查詢的結果,如示例5所示。

示例5

//修改示例4Main方法

var result = from stu in list where stu.Age == 18

select new (stu.Name,stu.Age);

Console.WriteLine("年齡為18的學員為:");

foreach (var stu in result)

{

Console.WriteLine(stu);

}

  

   

1.2.5 多級排序

處理了帶多個屬性的對象后,要考慮按多種方式進行排序的問題了,例如我們先按照班級排序,在按照年齡排序。代碼如下:

var result=from stu in list orderby stu.Class,stu.Age select stu;

還可以給字段添加Descending關鍵字。如

orderby stu.Class,stu.Age.deseending;

1.2.6 分組查詢

在Linq中還可以實現像Sql中的Group by語句一樣的分組統計功能。

示例6

var result=from stu in list

group stu by stu.Class into student

select new {Class=student.Key,Count=student.Count()};

   

var orderresult=from student in result

orderby student.Count descending

select student;

在分組查詢中的數據通過一個鍵(key)字段來分組,每個組中的所有程序都共享這個字段值,在此例中鍵字段是Class:

group stu by stu.Class

要計算每個組的數量,應該生成一個新的結果集student(可自定義):

group stu by stu.Class into student

1.2.7 Join查詢

Join可以用一個查詢搜索兩個列表中相關的數據,用關鍵字段把結果連接起來。類似於SQL中join(內連接)操作。如:

var result = from stu in list join scr in Scores

on stu.ID equals scr.ID

select new { stu.ID, stu.Name, scr.score };

   

foreach (var ss in result)

{

Console.WriteLine(ss);

}

   

1.3 Linq之方法語法

1.3.1 Lambda表達式

Lambda表達式用來實現一個匿名方法,其語法為:

(參數列表)=> 語句或語句塊

 

這是一個簡單的Lambda表達式: (item)=>item<1000;

運算符 "=>"稱為Lambda表達式。這個表達式定義了一個方法,其參數是item,如果item小於1000,該方法就返回ture,否則返回false。該方法是一個沒有名稱的匿名方法。

 

  1. 如果我們只有一個參數,我們也可以刪除(),代碼如下:

    item=>item<1000;

  2. 如果需要傳遞多個參數,那么必須將參數括在括號內

    (ints,item)=>ints.Contains(item);

  3. 在Lambda表達式中可以沒有參數,如下所示:

    ( ) =>Console.WriteLine("這是一個不帶參數的Lambda表達式");

  4. 如果正文表達式中有多條語句,那么必須用大括號將正文表達式括起來,如下所示:

    (ints, item) => {

    Console.WriteLine("這是包含多條語句的Lambda表達式");

    return ints.Contains(item);

    };

  5. Func委托

    當需要指定Lambda表達式返回結果的類型時,可以使用Func<T,TResult>委托。如下所示:

    Func<int[], bool> isContains= p=> p.Equals(10);

    int[] ints= { 5 ,2 ,0, 66, 32, 7};

    bool result=isContains(ints);

   

1.3.2 Linq中使用Lambda表達式

回顧示例2中的代碼:

var result = from n in names where n.StartsWith("s") select n;

我們可以用方法語法來實現:

var result = names.Where(n => n.StartsWith("s"));

我們發現,用法方法查詢語法更加簡潔。

  1. 過濾(篩選)

    上面代碼中Where()方法用來篩選,返回符合條件的子集。

  2. 排序(OrderBy、OrderByDescending、ThenBy 、ThenByDescending)

    對上面的查詢結果排序可以使用如下語句。

    var result = names.OrderBy(n => n).Where(n => n.StartsWith("s"));

    或者

    var result = names.Where(n => n.StartsWith("s")).OrderBy(n=>n);

    方法調用的順序不是固定的,只要Linq方法返回值為IEnumerable類型即可,可以按照容易理解的方式來使用。此規則適合於以后講到的其他方法。

    OrderBy()方法需要傳入一個Lambda表達式用來告訴它用於排序的方法是什么,我們傳送了最簡單的Lambda表達式n=>n,因為只需要按照元素本身排序。還可以向上一章所講那樣按照最后一個字母進行排序:n=>n.Substring(n.Length-1)

    為了給元素逆序排序,可以調用OrderByDescending()方法,使用方法和OrderBy()相同。

   

多級排序可以使用ThenBy()方法。例如:

var result=list.OrderBy(stu=>stu.Class)

.ThenBy(stu=>stu.Age)

.ThenBy(stu=>stu.Name)

.Select(stu=>new {stu.Name,stu.Age,stu.Class});

多字段列表可以用在查詢語法的OrderBy子句中。但在方法語法中第一項排序字段必須使用OrderBy()方法,隨后使用ThenBy()方法。

如果第一個字段是以降序排序,需要使用OrderByDescending()方法,其他字段降序排序需要使用ThenByDescending()方法。

  1. 投射(Select)

    Select()方法用於方法語法的投射。示例5的功能可以通過下面代碼實現。

    var result=list.Where(stu=>stu.Age==18)

    .Select(stu=>new {stu.Name,stu.Age,stu.Class});

  2. Any 和 All

    我們常常需要一類查詢,確定數據是否滿足某個條件,或者確保所有的數據都滿足某個條件。例如,需要確定某個產品是否沒有貨了(庫存為0)。

    Linq提供了兩個布爾方法:Any() 和 All(),它們可以快速確定對於數據而言,某個條件是true還是false。如下面示例所示:

bool anyStu = list.Any(stu => stu.Sex == "");

if (anyStu)

{

Console.WriteLine("學員中有男同學");

}

else

{

Console.WriteLine("學員中沒有男同學");

}

bool allStu = list.All(stu => stu.Sex == "");

if (allStu)

{

Console.WriteLine("學員中全部是男同學");

}

else

{

Console.WriteLine("學員中不全是男同學");

}

   

  1. Take 和 Skip

    Take()方法對應SQL語句中的Top運算符。與Take()方法相反的是Skip()方法,它可以跳過前n個結果,返回剩余的結果。例如:

var result = list.OrderBy(stu => stu.Age);

Console.WriteLine("年齡最小的兩名學員是:");

foreach (var stu in result.Take(2))

{

Console.WriteLine(stu);

}

Console.WriteLine("其他學員依次為:");

foreach (var stu in result.Skip(2))

{

Console.WriteLine(stu);

}

   

  1. First 和 FirstOrDefault

    First()方法用來查找集合中第一個匹配的元素,如果沒有找到匹配的結果則會引發一個異常。可以使用FirstOrDefault()方法避免異常的發生,若沒有找到則返回有一個空。

    示例代碼:

Console.WriteLine("姓名為lisi的同學信息:");

Console.WriteLine(list.First(stu => stu.Name == "lisi"));

Console.WriteLine("姓名為hanjiu的同學信息:");

Console.WriteLine(list.FirstOrDefault(stu => stu.Name == "hanjiu"));

   

  1. Single和SingleOrDefault

    相當於First()和FirstOrDefault(),但是如果不止一個匹配元素則拋出異常。

  2. 集合方法

    Count:返回集合的個數。

    Min/Max:返回集合的最小/大值。

    Sum:返回集合元素的和。

    Average:返回集合元素的平均值。

    示例代碼:

int[] numbers = { 28, 32, 14 };

   

int fullCount = numbers .Count(); // 3

int digitCount = "pa55w0rd".Count(c => char.IsDigit(c)); // 3

int smallest = numbers.Min(); // 14;

int largest = numbers.Max(); // 32;

int smallest = numbers.Max(n => n % 10); // 8;

decimal sumTotal = numbers.Sum(); // 15

decimal average = numbers.Average(); // 5

  

   

   

本文只介紹了Linq的基本用法,尚有很多高級用法有待各位自行查閱資料進一步學習。

   

   

   

   

   

   

   

   

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM