Entity Framework技術系列之7:LINQ to Entities

來源:互聯網
上載者:User
前言

LINQ(Language Integrated Query,Language-integrated Query (LINQ))是一組用於C#和VB.NET語言的擴充,它允許編寫C#或者VB.NET代碼,以與查詢資料庫相同的方式操作記憶體資料。LINQ提Entity Framework技術系列之7:LINQ to Entities供了豐富的類似SQL的查詢文法,功能強大且容易上手。匯總展示了LINQ技術的官方實現集合:

 

1官方LINQ實現匯總圖

正如所示,LINQ to Entities 是LINQ技術在實體物件模型中的一種實現,它與LINQ to SQL以及LINQ to DataSets一起構成了LINQ to ADO.NET。LINQ to Entities可以產生eSQL,並支援使用LINQ文法對Entity Framework服務層進行查詢。展示了LINQ to Entities消費實體資料模型的技術細節:

 

2 LINQ to Entities與實體資料模型對應圖

 

相關概念

在開始瞭解LINQ to Entities之前,需要先對.NET Framework 3.5版本後對C#語言的幾個擴充特性做一些闡釋,這有助於我們更容易、更深刻的理解LINQ to Entities技術的原理與實現。

一、隱式執行個體化局部變數

.NET Framework 3.5後,執行個體化局部變數文法有了新的選擇:使用“var”關鍵字隱式類型化:

var user = new User();

隱式類型化文法與Javascript語言裡聲明變數的文法類似,它可以一定程度上簡化執行個體化局部變數的文法。但如果隱式執行個體化的作用僅限於此,那本文不會專門提及。隱式類型化更重要的用途是用於匿名型別的執行個體化。

需要提醒注意的是,只有局部變數執行個體化允許使用隱式執行個體化文法。這表示私人變數執行個體化無法享受該福利;同時,僅聲明變數或執行個體化對象為null也是不允許使用隱式執行個體化文法的。

二、對象初始化

對象初始化指在執行個體化對象時,即可對對象的屬性進行賦值:

1 var user = new User()2 {3     ID = Guid.NewGuid(),4     Account = "Apollo"5 };
三、匿名型別

LINQ to Entities的Select可以將實體類型投影為匿名型別,所以有必要對匿名型別作簡單介紹。匿名型別指的是不顯示宣告類型的細節,而是根據上下文環境需要,臨時聲明滿足需要的類型。由於該類型是臨時需要的,所以不必為之命名。匿名型別的聲明文法如下:

var user = new { ID = Guid.NewGuid(), Name = "Apollo" };
四、擴充方法

擴充方法是微軟為擴充已有架構而創造的一個文法糖,.NET Framework 3.5就是通過很多擴充方法實現了對.NET Framework 2.0的升級擴充的。擴充方法很神奇,被擴充的對象可以不知道擴充方法的存在,就能在行為上得到擴充。擴充方法也很蹩腳,如果使用者不知情,很可能不知道對象具有擴充行為;抑或知道有擴充方法,但是不知道要引用哪個擴充庫以使其支援擴充的行為。擴充方法的文法如下:

1 public static class UserExt2 {3     public static void Drink(this User user, object water)4     {5         …6     }7 }
五、Lambda運算式

Lambda運算式是由委託以及匿名方法發展而來的,它可將運算式或代碼塊(匿名方法)賦給一個變數,從而以最少量的輸入實現編碼目的。Lambda運算式一般配合IEnumerable<T>的靜態擴充方法使用,完成對象集合的快捷查詢操作。Lambda運算式的文法如下:

var user = db.Users.FirstOrDefault(o => o.Account == "Apollo");
六、標準查詢操作符

System.Linq.Enumerable靜態類聲明了一套標準查詢操作符(Standard Query Operators,SQO)方法集合。標準查詢操作符的文法和標準SQL很相似,這不是偶然,而是微軟有意為之,以使熟悉SQL的程式員們更容易上手。標準查詢操作符的基本文法如下:

1 using (var db = new EntityContext())2 {3     var roles = from o in db.Users4                where o.Account == "Apollo"5                select o.Roles;6     …7 }

標準查詢操作符和Lambda運算式的關係非常密切。編譯器會將上訴運算式轉化為下列以Lambda運算式為參數的顯式擴充方法調用序列:

1 using (var db = new EntityContext())2 {3     var roles = db.Users.Where(o => o.Account == "Apollo").Select(o => o.Roles);4 }

 

標準查詢操作符

接下來,將針對資料查詢操作中常用的條件查詢、投影、分區、排序、分組、集合、元素、量詞和聚集等標準查詢操作符進行分類介紹。

一、條件操作符

條件操作符Where類似於SQL中的WHERE子句,用於實現條件查詢。下列擴充方法運算式查詢滿足條件“角色不為空白”的使用者集合:

var user = db.Users.Where(o => o.Roles != null);

對應的標準查詢操作符運算式為:

1 var users = from o in db.Users2             where o.Roles != null3             select o;
二、投影操作符

投影操作符Select類似於SQL中的SELECT子句,將對象投影為一個匿名型別執行個體,用於控制指定查詢迭代器顯示或者處理的對象屬性。另外,需要注意的是,擴充方法運算式中的Select操作符並非必須的,省略模式下,會返回完整的被投影對象。下列擴充方法運算式將使用者的帳號和密碼資訊投影為一個匿名型別:

var users = db.Users.Select(o => new { o.Account, o.Password });

對應的標準查詢操作符運算式為:

1 var users = from o in db.Users2             select new { o.Account, o.Password };
三、分區操作符

分區操作符實現對象的分區操作。其中,Take操作符類似於SQL中的TOP操作符,下列擴充方法運算式返回前5個使用者物件:

var users = db.Users.OrderBy(o => o.Roles.Count).Take(5);

Skip操作符用於跳過指定個數對象並返回序列中的剩餘對象,下列擴充方法運算式返回除前10個使用者外的剩餘使用者:

var users = db.Users.OrderBy(o => o.Roles.Count).Skip(10);

TakeWhile操作符用於返回條件運算式值為真時的相鄰元素集合,下列擴充方法運算式返回第一個擁有3個角色的使用者之前的所有使用者集合:

var users = db.Users.OrderBy(o => o.Roles.Count).TakeWhile(o => o.Roles.Count == 3);

SkipWhile操作符用於跳過條件運算式值為真時的元素,並返回剩下的元素集合,下列擴充方法運算式返回第一個擁有3個角色的使用者之後的所有使用者集合:

var users = db.Users.OrderBy(o => o.Roles.Count).SkipWhile(o => o.Roles == 3);
四、排序操作符

排序操作符實現對象的排序功能,包括OrderBy、OrderByDescending、ThenBy、ThenByDescending和Reverse五個操作符。其中OrderBy操作符實現對象的升序排列,相當於SQL中的ORDER BY ASC子句,下列擴充方法運算式實現使用者按擁有的角色數進行升序排列:

var users = db.Users.OrderBy(o => o.Roles.Count);

對應的標準查詢操作符運算式為:

1 var users = from o in db.Users2             orderby o.Roles.Count3             select o;

OrderByDescending操作符實現對象的降序排列,相當於SQL中的ORDER BY DESC子句,下列擴充方法運算式實現使用者按擁有的角色數進行降序排列:

var users = db.Users.OrderByDescending(o => o.Roles.Count);

對應的標準查詢操作符運算式為:

1 var users = from o in db.Users2             orderby o.Roles.Count descending3             select o;

ThenBy、ThenByDescending和Reverse操作符只能針對IOrderedEnumerable介面對象使用,所以一般緊跟在OrderBy/OrderByDesending操作符方法後使用。ThenBy操作符由編譯器翻譯為對OrderBy操作符的再次調用;ThenByDescending操作符由編譯器翻譯為對OrderByDescending操作符的再次調用;Reverse操作符實現對象的排序反向。這裡不再一一舉例。

五、分組操作符

分組操作符GroupBy類似於SQL中的GROUP BY子句,實現對象的分組操作。下列擴充方法運算式實現使用者物件按擁有的角色數量進行分組:

var users = db.Users.GroupBy(o => o.Roles.Count);

對應的標準查詢操作符運算式為:

1 var users = from o in db.Users2             group o by o.Roles.Count into g3             select new { RoleCount = g.Key, Group = g };
六、集合操作符

集合操作符包括Distinct、Union、intersect和Except四個操作符,除Distinct外,其他三個操作符都可將兩個序列組合成一個序列。Distinct操作符類似於SQL中的DISTINCT關鍵字,用於刪除序列中具有重複值的對象。下列擴充方法運算式實現將使用者角色中的重複角色刪除功能:

var roles = user.Roles.Distinct();

Union操作符類似於SQL中的UNION關鍵字,用於求具有同樣結構的兩個序列的並集。下列擴充方法運算式實現將使用者1和使用者2所擁有的角色群組合成一個角色集合,並排除其中重複的角色:

var roles = user1.Roles.Union(user2.Roles);

Intersect操作符類似於SQL中的INTERSECT關鍵字,用於求具有同樣結構的兩個序列的交集。下列擴充方法運算式返回使用者1和使用者2都具有的角色集合:

var roles = user1.Roles.Intersect(user2.Roles);

Except操作符類似於SQL中的EXCEPT關鍵字,用於返回第一個序列中有、但第二個序列中沒有的對象集合。下列擴充方法運算式返回使用者1擁有,而使用者2沒有的角色集合:

var roles = user1.Roles.Except(user2.Roles);
七、元素操作符

元素操作符包括兩組操作符,分別是用於從一個IEnumerable<T>序列中返回滿足條件的單個對象或無滿足條件對象時拋異常的First、Last和Single操作符,以及返回滿足條件的單個對象或無滿足條件對象時返回Null 物件的FirstOrDefault、LastOrDefault和SingleOrDefault操作符。其中First和FirstOrDefault操作符用於返回第一個滿足條件的對象。下列擴充方法運算式返回第一個擁有三個角色的使用者:

var user = db.Users.FirstOrDefault(o => o.Roles.Count == 3);

Last和LastOrDefault操作符用於返回最後一個滿足條件的對象。下列擴充方法運算式返回最後一個擁有三個角色的使用者:

var user = db.Users.LastOrDefault(o => o.Roles.Count == 3);

Single和SingleOrDefault操作符用於返回滿足條件的序列中的唯一元素,如果序列中包含不止一個元素,將會拋異常。下列擴充方法運算式返回帳號為“Apollo”的唯一使用者,如果有多個使用者帳號都為“Apollo”,則拋異常:

var user = db.Users.SingleOrDefault(o => o.Account == "Apollo");
八、量詞操作符

量詞操作符包括 Any、All和Contains三個操作符,用於檢查序列中是否有一些對象或所有對象滿足條件。其中,Any操作符用於檢查序列中是否有任何一個對象滿足條件。下列擴充方法運算式當有任何一個使用者擁有三個角色時返回真,否則返回假:

var result = db.Users.Any(o => o.Roles.Count == 3);

All操作符用於檢查序列中是否所有對象均滿足條件。下列擴充方法運算式當所有使用者均擁有三個角色時返回真,否則返回假:

var result = db.Users.All(o => o.Roles.Count == 3);

Contains操作符用於檢查序列中是否包含指定的對象。下列擴充方法運算式當集合中包含使用者1則返回真,否則返回假:

var result = db.Users.Where(o => o.Roles.Count == 3).Contains(user1);
九、聚集操作符

聚集操作符包括Count、Min、Max、Sum和Average等多個操作符,用於對對象集合進行統計計算。其中,Count操作符類似於SQL中的COUNT關鍵字,用於計算序列中滿足條件的對象個數。下列擴充方法運算式返回擁有3個角色的使用者數量:

var result = db.Users.Count(o => o.Roles.Count == 3);

Min操作符類似於SQL中的MIN關鍵字,用於返回按條件計算的最小值。下列擴充方法運算式返回擁有最少角色數量的使用者所擁有的角色數量:

var result = db.Users.Min(o => o.Roles.Count);

Max操作符類似於SQL中的MAX關鍵字,用於返回按條件計算的最大值。下列擴充方法運算式返回擁有角色數量最多的使用者所擁有的角色數量:

var result = db.Users.Max(o => o.Roles.Count);

Sum操作符類似於SQL中的SUM關鍵字,用於返回按條件計算的總數。下列擴充方法運算式返回已賦予使用者的所有角色總數:

var result = db.Users.Sum(o => o.Roles.Count);

Average操作符類似於SQL中的AVERAGE關鍵字,用於返回按條件計算的平均值。下列擴充方法運算式,用於返回使用者所擁有的角色平均數:

var result = db.Users.Average(o => o.Roles.Count);

 

總結

本文首先給出了LINQ技術的官方實現集合,以及LINQ to Entities實現的技術細節;然後概要介紹了與LINQ to Entities相關的幾個基本概念;最後對LINQ to Entities常用的標準查詢操作符的使用進行了分類介紹,從中也可以看出LINQ to Entities和SQL的功能基本是一一對應的。

下一篇文章將綜合運用本系列前文所介紹的所有技術,完成一個RBAC模型的設計與實現。

 

附件下載:本文PDF版本

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.