您好,登錄后才能下訂單哦!
這篇文章主要講解了“LINQ標準查詢操作符的用法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“LINQ標準查詢操作符的用法”吧!
LINQ對于開發人員來說很方便,不過掌握LINQ的標準查詢操作符是基礎中的基礎。本文將為大家詳細講解LINQ標準查詢操作符的用法,希望對大家有所幫助。語言集成查詢 (LINQ) 允許開發人員通過強類型化語法使用 Microsoft® .NET Framework 3.5 代碼編寫類似 SQL 的查詢。然后,各種 LINQ 提供程序,如 LINQ to Objects(可利用它根據對象層次結構編寫查詢)和 LINQ to Entities(可利用它根據實體框架的概念模型編寫查詢)可根據代表數據存儲的細微差別來有效處理這些查詢。
除強類型化語法外,LINQ 查詢還具有一個標準查詢操作符庫來增強其功能。這些標準查詢操作符對序列進行運算并可執行各種運算,如確定序列中是否存在某個值以及對序列運行合計函數(如求和)。
在本月的專欄中,我將使用 LINQ 來執行實際的查詢和運算(會用到 LINQ to Objects 和 LINQ to Entities)。我將查詢一個實體集合并使用其導航屬性深入研究一組具備層次結構的實體。我還會為您演示如何對數組和集合應用多個標準查詢操作符。并展示如何使用 lambda 表達式強化 LINQ 的標準查詢操作符,以及如何利用它們來從序列解析特定信息并對序列執行復雜的邏輯運算。本專欄的下載中提供有所有代碼示例(請參見 msdn.microsoft.com/msdnmag/code08.aspx)。
操作符和 LINQ
LINQ 自身功能非常強大,無論使用的是 LINQ to XML、LINQ to DataSets、LINQ to Entities、LINQ to Objects 還是附帶的任何其他 LINQ 提供程序。LINQ 的核心功能在于其強類型化查詢語法,它可用于任意此類提供程序。當將 LINQ 與一個或多個標準查詢操作符結合使用時,會得到一個功能更為強大的工具集,從而可精細地控制一組數據。
標準查詢操作符在 System.Linq 命名空間中的 System.Core.dll 程序集中作為靜態類 Enumerable 和 Queryable 的擴展方法存在,并且可用于實現 IEnumerable
可輕松地確定處理特定任務時所擁有的操作符。如果要在 LINQ 查詢中使用操作符,可使用 Queryable 靜態類可用擴展方法中的操作符。如果要對實現 IEnumerable
操作符類型
操作符有多種類型(使用對象瀏覽器查看 Enumerable 和 Queryable 類即可找到所有操作符)。以字母順序顯示了不同類型操作符的分類。可利用它來大致了解一下操作符所提供的功能。我將使用 LINQ to Objects 和 LINQ to Entities 展示一小組此類操作符,以顯示它們如何為實際應用程序帶來好處。
FigureACategories of Operators
Lambda 表達式
許多標準查詢操作符在對序列執行運算時都使用 Func 委托來處理單個元素。Lambda 表達式可與標準查詢操作符結合使用以代表委托。lambda 表達式是創建委托實現的簡略表達形式,并可用于匿名委托適用的所有場合。C# 和 Visual Basic® .NET 均支持 Lambda 表達式。但是,必須注意:由于 Visual Basic .NET 尚不支持匿名方法,Lambda 表達式可能僅包含一個語句。
讓我們來看看如何對一個整數數組使用 Single 操作符。這個整數數組的每個元素代表 2 的 1 到 10 次方。先創建此數組,然后使用 Single 操作符來檢索滿足 Lambda 表達式中指定條件的單個整數元素:
int[] nums = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; int singleNum = nums.Single(x => x > 16 && x < 64); Console.WriteLine(singleNum.ToString());
Lambda 表達式包含多個關鍵部分。Lambda 表達式首先定義傳入委托的變量。在以上代碼示例中,x(在 => 操作符左側聲明)是參數,代表傳遞給它的 nums 數組中的每個元素。Lambda 表達式的剩余部分代表數組中每個元素的評估邏輯。可使用匿名委托輕松地重新編寫以上表達式,如下所示:
int singleNum = nums.Single( delegate(int x) {return (x > 16 && x < 64); } ) ;
但是,此代碼的可讀性不及 Lambda 表達式。C# 2.0 引入了可使委托的傳遞稍微輕松些的匿名委托;但是,Lambda 表達式的簡潔語法可使其更加簡單。
First 和 Single
如果必須從序列中提取一個值,First、FirstOrDefault、Single 和 SingleOrDefault 操作符都非常有用。First 方法返回序列中的***個元素。First 有一個重載方法,可使用它來傳入 Lambda 表達式來代表一個條件。例如,如果要返回整數序列中整數元素大于 50 的***個元素,可使用以下代碼示例:
int[] nums = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; int num1 = nums.First(); int num2 = nums.First(x => x > 50); int num3 = nums.FirstOrDefault(x => x > 5000); Console.WriteLine( num1.ToString() + "-" + num2.ToString() + "-" + num3.ToString());
此代碼會查找***個元素 (1)、大于 50 的***個元素 (64) 以及大于 5,000 的***個元素。由于數組中沒有元素滿足第三個 Lambda 表達式(數組中無整數大于 5,000),則如果代碼使用的是 First 操作符而非 FirstOrDefault,則會引發異常。在使用 FirstOrDefault 操作符時,如果沒有元素滿足 Lambda 表達式,則會返回 0。First 操作符也可用于 LINQ to Entities 查詢,如下所示:
using (Entities entities = new Entities()) { var query = (from c in entities.Customers select c).First(c => c.City.Equals("London")); Console.WriteLine(query.CompanyName); }
在此示例中,將返回 London 城中的***個客戶。正如您所看到的,當 First 方法用于各種 LINQ 提供程序(在本例中為 LINQ to Objects 和 LINQ to Entities)時,所用的語法并不會更改。
在 LINQ to Entities 上下文中,First 操作符非常有用,尤其是您知道會從查詢返回單個記錄時。例如,您可能有個查詢,它常在給出 CustomerID 時獲取一條客戶記錄。這種情況總是返回 0 或 1 條記錄,因此,得到一個序列不如就得到一個實體本身。換句話說,您寧愿獲取 Customer 實體而非 1 個 Customer 實體序列。First 方法在某種怦下非常有用,如以下代碼段所示。(由于實體框架不會嘗試在客戶端和服務器之間分發單個查詢的執行,并且 LINQ to Entities 不支持 Single 方法,因此使用 First 方法是個輕松的替代方法。)
using (Entities entities = new Entities()) { var query = (from c in entities.Customers where c.CustomerID.Equals("BOLID") select c).First(); Console.WriteLine(query.CompanyName); }
聚合、層次結構和投影
在 LINQ to Entities 查詢中使用聚合操作符(如 Sum)可有助于簡化查詢。例如,以下代碼檢索訂單總額大于 $10,000 的一個訂單序列:
using (Entities entities = new Entities()) { var query = from o in entities.Orders where o.OrderDetails.Sum( od => od.UnitPrice * od.Quantity) >= 10000 select o; foreach (Orders order in query) Console.WriteLine(order.OrderID); }
由于 LINQ 可查詢層次結構實體集合,因此標準查詢操作符也可用于對嵌套實體序列執行運算。當必須計算或詢問派生數據時,這一點非常有用。派生數據可能僅存在于其基本窗體中,如客戶訂單的詳細信息僅包含單價和數量值。在本例中,未在模型中的任何位置提供代表訂單總金額的聚合數據。然而,通過在 LINQ 查詢中應用 Sum 操作符,仍可檢索消費金額超過 $20,000 的所有客戶,如下所示:
using (Entities entities = new Entities()) { var query = from c in entities.Customers where c.Orders.Sum( o => o.OrderDetails.Sum( od => od.UnitPrice * od.Quantity)) >= 25000 select c; foreach (Customers customer in query) Console.WriteLine(customer.CompanyName); }
此示例展示了如何在 LINQ 查詢的多個層次應用標準查詢操作符。查詢最終會返回一個 Customers 實體序列,但為達到此目的,它必須首先深入每個客戶的訂單以及每個訂單的訂單詳細信息獲取所需數據,這樣才可以計算每項的價格,匯總每個訂單的項目,然后匯總每個客戶的總額。
Count 操作符是另一聚合標準查詢操作符。可通過使用以下代碼確定有多少客戶的消費金額超過 $25,000:
using (Entities entities = new Entities()) { var query = (from c in entities.Customers where c.Orders.Sum( o => o.OrderDetails.Sum( od => od.UnitPrice * od.Quantity)) >= 25000 select c).Count(); Console.WriteLine(query); }
可使用 Max 操作符來確定***客戶。以下代碼示例將返回消費***的客戶所花費的金額。它在層次結構的多個層級中組合使用 Sum 和 Max 聚合操作符:
using (Entities entities = new Entities()) { var query = (from c in entities.Customers where c.Orders.Sum( o => o.OrderDetails.Sum( od => od.UnitPrice * od.Quantity)) >= 25000 select c).Count(); Console.WriteLine(query); }
投影和排序
您可能還注意到我在之前的示例中暗藏了一個投影。在使用 Max 操作符之前,LINQ 查詢并不返回客戶列表。而是會返回一個投影,此投影創建了包含 CustomerID 屬性和 Total 屬性(客戶的整個消費金額)的一個新實體。投影是 LINQ 必不可少的一部分,如前一示例所示,將它們投影到序列中后,就可使用標準查詢操作符來進一步處理它們。
顯示了如何創建一個新實體投影,其中包含 CustomerID 和客戶的訂單總金額(使用之前討論的 Sum 操作符)。還使用 OrderByDescending 操作符來按計算總額對投影實體序列進行排序。如果兩個客戶總額相同,還會使用另一排序操作符來進一步定義順序。例如,還可使用以下代碼修正的 foreach 語句以進一步限定排序規則:
Figure1Aggregates, Projections, and Ordering using (Entities entities = new Entities()) { var query = from c in entities.Customers where c.Orders.Sum( o => o.OrderDetails.Sum(od => od.UnitPrice)) > 0 select new { c.CustomerID, Total = c.Orders.Sum( o => o.OrderDetails.Sum(od => od.UnitPrice)) }; foreach (var item in query.OrderByDescending(x => x.Total)) Console.WriteLine(item.CustomerID + " == " + item.Total); } foreach (var item in query.OrderByDescending(x => x.Total) .ThenBy(x => x.CustomerID)) { Console.WriteLine(item.CustomerID + " == " + item.Total); }
在該代碼段中,我添加了 ThenBy 操作符和一個 Lambda 表達式,以表示序列應首先按 Total 屬性降序排列,然后按投影的 CustomerID 屬性升序排列。
限定符和轉換
如果需要確定序列中是否存在某個值,可使用標準查詢操作符 Any。限定符(如 Any、All 和 Contains)會搜索元素序列,并評估序列是否滿足 lambda 表達式的條件。如果需檢查序列以確定某些事宜(例如:是否存在來自特定地址的客戶、所有客戶是否來自同一國家或者任意其他分析確定性問題),它將非常有用。
例如,以下 LINQ 查詢會檢查是否來自 United Kingdom 的所有客戶都位于 London。它使用限定符 All 并將其傳遞給僅評估城市是否為 London 的 lambda 表達式。如果序列中的每個元素都滿足此條件并且 lambda 表達式返回 true,然后 All 操作符會返回 true:
using (Entities entities = new Entities()) { bool allUKCustomerAreFromLondon = (from c in entities.Customers where c.Country == "UK" select c).All( c => c.City.Equals("London")); Console.WriteLine(allUKCustomerAreFromLondon ? "Yes" : "No"); }
需在此查詢中詢問的另一問題是序列中是否有來自 United Kingdom 的 Cowes 的實體。對于此問題,可使用 Any 限定符來計算序列,如下所示:
using (Entities entities = new Entities()) { bool isOneUKCustomerFromCowes = (from c in entities.Customers where c.Country == "UK" select c).Any( c => c.City.Equals("Cowes")); Console.WriteLine(isOneUKCustomerFromCowes? "Yes" : "No"); }
Contains 操作符在評估序列中是否包括您所查找的項目時類似于 Any 操作符。Any 操作符可確定序列的某個項中是否存在某個值,而 Contains 操作符則確定序列中是否存在特定項目實例。例如,在將某個對象添加到序列中之前,您可能希望確保序列中并未包含該對象。展示了如何檢查。
Figure2Using Contains and Conversion
using (Entities entities = new Entities()) { Customers customerBSBEV = (from c in entities.Customers where c.CustomerID == "BSBEV" select c).First(); var customersUK = from c in entities.Customers where c.Country == "UK" select c; bool isCustomerInSequence = customersUK.Contains(customerBSBEV); Console.WriteLine(isCustomerInSequence? "Yes" : "No"); }
請注意:首先針對 BSBEV 客戶檢索 Customers 實體。然后,檢索客戶來自 United Kingdom 的 Customers 實體序列。***,使用 Contains 操作符來檢查 Customers 序列是否包含 customerBSBEV 變量的實例。
顯示的 Contains 操作符實現適用于可基于其實際實例信心十足地比較對象的場合。但是,如果需要 Contains 操作符根據邏輯標識進行測試又該如何呢?幸運的是,Contains 操作符包含一個重載,可使用它來傳遞實現 IEqualityComparer
using (Entities entities = new Entities()) { ... bool isCustomerInSequence = customersUK.Contains(customerBSBEV, new CustomerComparer()); Console.WriteLine(isCustomerInSequence? "Yes" : "No"); }
其中 CustomerComparer 定義為
private class CustomerComparer : IEqualityComparer { public bool Equals(Customers x, Customers y) { if (x == null || y == null) return false; return x.CustomerID.Equals(y.CustomerID); } ... }
結束語
有許多標準查詢操作符均可定義為 Enumerable 和 Queryable 序列類的擴展方法。考試大提示如之前所示,這些操作符有助于擴展 LINQ 的功能。我還展示了結合使用多個 .NET Framework 3.5 新增強功能(包括 lambda 表達式、LINQ、實體框架和隱式類型化變量)來更加輕松地編寫功能強大的代碼和邏輯。
感謝各位的閱讀,以上就是“LINQ標準查詢操作符的用法”的內容了,經過本文的學習后,相信大家對LINQ標準查詢操作符的用法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。