最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。 十年河東十年河西,莫欺少年窮 學無止境,精益求精 最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。 十年河東十年河西,莫欺少年窮 學無止境,精益求精 最近悟出來一 ...
最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。
十年河東十年河西,莫欺少年窮
學無止境,精益求精
LINQ to SQL語句(1)之Where
適用場景:實現過濾,查詢等功能。
說明:與SQL命令中的Where作用相似,都是起到範圍限定也就是過濾作用的,而判斷條件就是它後面所接的子句。Where操作包括3種形式,分別為簡單形式、關係條件形式、First()形式。下麵分別用實例舉例下:
1.簡單形式:
例如:使用where篩選在倫敦的客戶
var q = from c in db.Customers where c.City == "London" select c;
再如:篩選1994 年或之後雇用的雇員:
var q = from e in db.Employees where e.HireDate >= new DateTime(1994, 1, 1) select e;
2.關係條件形式:
篩選庫存量在訂貨點水平之下但未斷貨的產品:
var q = from p in db.Products where p.UnitsInStock <= p.ReorderLevel && !p.Discontinued select p;
篩選出UnitPrice 大於10 或已停產的產品:
var q = from p in db.Products where p.UnitPrice > 10m || p.Discontinued select p;
下麵這個例子是調用兩次where以篩選出UnitPrice大於10且已停產的產品。
var q = db.Products.Where(p=>p.UnitPrice > 10m).Where(p=>p.Discontinued);
3.First()形式:
返回集合中的一個元素,其實質就是在SQL語句中加TOP (1)。
簡單用法:選擇表中的第一個發貨方。
Shipper shipper = db.Shippers.First();
元素:選擇CustomerID 為“BONAP”的單個客戶
Customer cust = db.Customers.First(c => c.CustomerID == "BONAP");
條件:選擇運費大於 10.00 的訂單:
Order ord = db.Orders.First(o => o.Freight > 10.00M);
LINQ to SQL語句(2)之Select/Distinct
適用場景:o(∩_∩)o… 查詢唄。
說明:和SQL命令中的select作用相似但位置不同,查詢表達式中的select及所接子句是放在表達式最後並把子句中的變數也就是結果返回回來;延遲。Select/Distinct操作包括9種形式,分別為簡單用法、匿名類型形式、條件形式、指定類型形式、篩選形式、整形類型形式、嵌套類型形式、本地方法調用形式、Distinct形式。
1.簡單用法:
這個示例返回僅含客戶聯繫人姓名的序列。
var q = from c in db.Customers select c.ContactName;
註意:這個語句只是一個聲明或者一個描述,並沒有真正把數據取出來,只有當你需要該數據的時候,它才會執行這個語句,這就是延遲載入(deferred loading)。如果,在聲明的時候就返回的結果集是對象的集合。你可以使用ToList() 或ToArray()方法把查詢結果先進行保存,然後再對這個集合進行查詢。當然延遲載入(deferred loading)可以像拼接SQL語句那樣拼接查詢語法,再執行它。
2.匿名類型形式:
說明:匿名類型是C#3.0中新特性。其實質是編譯器根據我們自定義自動產生一個匿名的類來幫助我們實現臨時變數的儲存。匿名類型還依賴於另外一個特性:支持根據property來創建對象。比如,var d = new { Name = "s" };編譯器自動產生一個有property叫做Name的匿名類,然後按這個類型分配記憶體,並初始化對象。但是var d = new {"s"};是編譯不通過的。因為,編譯器不知道匿名類中的property的名字。例如string c = "d";var d = new { c}; 則是可以通過編譯的。編譯器會創建一個叫做匿名類帶有叫c的property。 例如下例:new{c,ContactName,c.Phone};ContactName和Phone都是在映射文件中定義與表中欄位相對應的property。編譯器讀取數據並創建對象時,會創建一個匿名類,這個類有兩個屬性,為ContactName和Phone,然後根據數據初始化對象。另外編譯器還可以重命名property的名字。
var q = from c in db.Customers select new {c.ContactName, c.Phone};
上面語句描述:使用 SELECT 和匿名類型返回僅含客戶聯繫人姓名和電話號碼的序列
var q = from e in db.Employees select new { Name = e.FirstName + " " + e.LastName, Phone = e.HomePhone };
上面語句描述:使用SELECT和匿名類型返回僅含雇員姓名和電話號碼的序列,並將FirstName和LastName欄位合併為一個欄位“Name”,此外在所得的序列中將HomePhone欄位重命名為Phone。
var q = from p in db.Products select new { p.ProductID, HalfPrice = p.UnitPrice / 2 };
上面語句描述:使用SELECT和匿名類型返回所有產品的ID以及HalfPrice(設置為產品單價除以2所得的值)的序列。
3.條件形式:
說明:生成SQL語句為:case when condition then else。
var q = from p in db.Products select new { p.ProductName, Availability = p.UnitsInStock - p.UnitsOnOrder < 0 ? "Out Of Stock" : "In Stock" };
上面語句描述:使用SELECT和條件語句返回產品名稱和產品供貨狀態的序列。
4.指定類型形式:
說明:該形式返回你自定義類型的對象集。
var q = from e in db.Employees select new Name { FirstName = e.FirstName, LastName = e.LastName };
上面語句描述:使用SELECT和已知類型返回雇員姓名的序列。
5.篩選形式:
說明:結合where使用,起到過濾作用。
var q = from c in db.Customers where c.City == "London" select c.ContactName;
上面語句描述:使用SELECT和WHERE返回僅含倫敦客戶聯繫人姓名的序列。
6.shaped形式(整形類型):
說明:其select操作使用了匿名對象,而這個匿名對象中,其屬性也是個匿名對象。
var q = from c in db.Customers select new { c.CustomerID, CompanyInfo = new {c.CompanyName, c.City, c.Country}, ContactInfo = new {c.ContactName, c.ContactTitle} };
語句描述:使用SELECT 和匿名類型返回有關客戶的數據的整形子集。查詢顧客的ID和公司信息(公司名稱,城市,國家)以及聯繫信息(聯繫人和職位)。
7.嵌套類型形式:
說明:返回的對象集中的每個對象DiscountedProducts屬性中,又包含一個集合。也就是每個對象也是一個集合類。
var q = from o in db.Orders select new { o.OrderID, DiscountedProducts = from od in o.OrderDetails where od.Discount > 0.0 select od, FreeShippingDiscount = o.Freight };
語句描述:使用嵌套查詢返回所有訂單及其OrderID 的序列、打折訂單中項目的子序列以及免送貨所省下的金額。
8.本地方法調用形式(LocalMethodCall):
這個例子在查詢中調用本地方法PhoneNumberConverter將電話號碼轉換為國際格式。
var q = from c in db.Customers where c.Country == "UK" || c.Country == "USA" select new { c.CustomerID, c.CompanyName, Phone = c.Phone, InternationalPhone = PhoneNumberConverter(c.Country, c.Phone) };
PhoneNumberConverter方法如下:
public string PhoneNumberConverter(string Country, string Phone) { Phone = Phone.Replace(" ", "").Replace(")", ")-"); switch (Country) { case "USA": return "1-" + Phone; case "UK": return "44-" + Phone; default: return Phone; } }
下麵也是使用了這個方法將電話號碼轉換為國際格式並創建XDocument
XDocument doc = new XDocument( new XElement("Customers", from c in db.Customers where c.Country == "UK" || c.Country == "USA" select (new XElement("Customer", new XAttribute("CustomerID", c.CustomerID), new XAttribute("CompanyName", c.CompanyName), new XAttribute("InterationalPhone", PhoneNumberConverter(c.Country, c.Phone)) ))));
9.Distinct形式:
說明:篩選欄位中不相同的值。用於查詢不重覆的結果集。生成SQL語句為:SELECT DISTINCT [City] FROM [Customers]
var q = ( from c in db.Customers select c.City ) .Distinct();
語句描述:查詢顧客覆蓋的國家。
LINQ to SQL語句(3)之Count/Sum/Min/Max/Avg
適用場景:統計數據吧,比如統計一些數據的個數,求和,最小值,最大值,平均數。
Count
說明:返回集合中的元素個數,返回INT類型;不延遲。生成SQL語句為:SELECT COUNT(*) FROM
1.簡單形式:
得到資料庫中客戶的數量:
var q = db.Customers.Count();
2.帶條件形式:
得到資料庫中未斷貨產品的數量:
var q = db.Products.Count(p => !p.Discontinued);
LongCount
說明:返回集合中的元素個數,返回LONG類型;不延遲。對於元素個數較多的集合可視情況可以選用LongCount來統計元素個數,它返回long類型,比較精確。生成SQL語句為:SELECT COUNT_BIG(*) FROM
var q = db.Customers.LongCount();
Sum
說明:返回集合中數值類型元素之和,集合應為INT類型集合;不延遲。生成SQL語句為:SELECT SUM(…) FROM
1.簡單形式:
得到所有訂單的總運費:
var q = db.Orders.Select(o => o.Freight).Sum();
2.映射形式:
得到所有產品的訂貨總數:
var q = db.Products.Sum(p => p.UnitsOnOrder);
Min
說明:返回集合中元素的最小值;不延遲。生成SQL語句為:SELECT MIN(…) FROM
1.簡單形式:
查找任意產品的最低單價:
var q = db.Products.Select(p => p.UnitPrice).Min();
2.映射形式:
查找任意訂單的最低運費:
var q = db.Orders.Min(o => o.Freight);
3.元素:
查找每個類別中單價最低的產品:
var categories = from p in db.Products group p by p.CategoryID into g select new { CategoryID = g.Key, CheapestProducts = from p2 in g where p2.UnitPrice == g.Min(p3 => p3.UnitPrice) select p2 };
Max
說明:返回集合中元素的最大值;不延遲。生成SQL語句為:SELECT MAX(…) FROM
1.簡單形式:
查找任意雇員的最近雇用日期:
var q = db.Employees.Select(e => e.HireDate).Max();
2.映射形式:
查找任意產品的最大庫存量:
var q = db.Products.Max(p => p.UnitsInStock);
3.元素:
查找每個類別中單價最高的產品:
var categories = from p in db.Products group p by p.CategoryID into g select new { g.Key, MostExpensiveProducts = from p2 in g where p2.UnitPrice == g.Max(p3 => p3.UnitPrice) select p2 };
Average
說明:返回集合中的數值類型元素的平均值。集合應為數字類型集合,其返回值類型為double;不延遲。生成SQL語句為:SELECT AVG(…) FROM
1.簡單形式:
得到所有訂單的平均運費:
var q = db.Orders.Select(o => o.Freight).Average();
2.映射形式:
得到所有產品的平均單價:
var q = db.Products.Average(p => p.UnitPrice);
3.元素:
查找每個類別中單價高於該類別平均單價的產品:
var categories = from p in db.Products group p by p.CategoryID into g select new { g.Key, ExpensiveProducts = from p2 in g where p2.UnitPrice > g.Average(p3 => p3.UnitPrice) select p2 };
Aggregate
說明:根據輸入的表達式獲取聚合值;不延遲。即是說:用一個種子值與當前元素通過指定的函數來進行對比來遍歷集合中的元素,符合條件的元素保留下來。如果沒有指定種子值的話,種子值預設為集合的第一個元素。
LINQ to SQL語句(4)之Join
適用場景:在我們表關係中有一對一關係,一對多關係,多對多關係等。對各個表之間的關係,就用這些實現對多個表的操作。
說明:在Join操作中,分別為Join(Join查詢), SelectMany(Select一對多選擇)和GroupJoin(分組Join查詢)。 該擴展方法對兩個序列中鍵匹配的元素進行inner join操作
SelectMany
說明:我們在寫查詢語句時,如果被翻譯成SelectMany需要滿足2個條件。1:查詢語句中沒有join和into,2:必須出現EntitySet。在我們表關係中有一對一關係,一對多關係,多對多關係等,下麵分別介紹一下。
1.一對多關係(1 to Many):
var q = from c in db.Customers from o in c.Orders where c.City == "London" select o;
語句描述:Customers與Orders是一對多關係。即Orders在Customers類中以EntitySet形式出現。所以第二個from是從c.Orders而不是db.Orders里進行篩選。這個例子在From子句中使用外鍵導航選擇倫敦客戶的所有訂單。
var q = from p in db.Products where p.Supplier.Country == "USA" && p.UnitsInStock == 0 select p;
語句描述:這一句使用了p.Supplier.Country條件,間接關聯了Supplier表。這個例子在Where子句中使用外鍵導航篩選其供應商在美國且缺貨的產品。生成SQL語句為:
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID],[t0].[QuantityPerUnit],[t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder],[t0].[ReorderLevel], [t0].[Discontinued] FROM [dbo].[Products] AS [t0] LEFT OUTER JOIN [dbo].[Suppliers] AS [t1] ON [t1].[SupplierID] = [t0].[SupplierID] WHERE ([t1].[Country] = @p0) AND ([t0].[UnitsInStock] = @p1) -- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [USA] -- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]
2.多對多關係(Many to Many):
var q = from e in db.Employees from et in e.EmployeeTerritories where e.City == "Seattle" select new { e.FirstName, e.LastName, et.Territory.TerritoryDescription };
說明:多對多關係一般會涉及三個表(如果有一個表是自關聯的,那有可能只有2個表)。這一句語句涉及Employees, EmployeeTerritories, Territories三個表。它們的關係是1:M:1。Employees和Territories沒有很明確的關係。
語句描述:這個例子在From子句中使用外鍵導航篩選在西雅圖的雇員,同時列出其所在地區。這條生成SQL語句為:
SELECT [t0].[FirstName], [t0].[LastName], [t2].[TerritoryDescription] FROM [dbo].[Employees] AS [t0] CROSS JOIN [dbo].[EmployeeTerritories] AS [t1] INNER JOIN [dbo].[Territories] AS [t2] ON [t2].[TerritoryID] = [t1].[TerritoryID] WHERE ([t0].[City] = @p0) AND ([t1].[EmployeeID] = [t0].[EmployeeID]) -- @p0: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [Seattle]
3.自聯接關係:
var q = from e1 in db.Employees from e2 in e1.Employees where e1.City == e2.City select new { FirstName1 = e1.FirstName, LastName1 = e1.LastName, FirstName2 = e2.FirstName, LastName2 = e2.LastName, e1.City };
語句描述:這個例子在select 子句中使用外鍵導航篩選成對的雇員,每對中一個雇員隸屬於另一個雇員,且兩個雇員都來自相同城市。生成SQL語句為:
SELECT [t0].[FirstName] AS [FirstName1], [t0].[LastName] AS [LastName1],[t1].[FirstName] AS [FirstName2], [t1].[LastName] AS [LastName2],[t0].[City] FROM [dbo].[Employees] AS [t0], [dbo].[Employees] AS [t1] WHERE ([t0].[City] = [t1].[City]) AND ([t1].[ReportsTo] = [t0].[EmployeeID])
GroupJoin
像上面所說的,沒有join和into,被翻譯成SelectMany,同時有join和into時,那麼就被翻譯為GroupJoin。在這裡into的概念是對其結果進行重新命名。
1.雙向聯接(Two way join):
此示例顯式聯接兩個表並從這兩個表投影出結果:
var q = from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID into orders select new { c.ContactName, OrderCount = orders.Count() };
說明:在一對多關係中,左邊是1,它每條記錄為c(from c in db.Customers),右邊是Many,其每條記錄叫做o ( join o in db.Orders ),每對應左邊的一個c,就會有一組o,那這一組o,就叫做orders,也就是說,我們把一組o命名為orders,這就是into用途。這也就是為什麼在select語句中,orders可以調用聚合函數Count。在T-SQL中,使用其內嵌的T-SQL返回值作為欄位值。如圖所示:
生成SQL語句為:
SELECT [t0].[ContactName], ( SELECT COUNT(*) FROM [dbo].[Orders] AS [t1] WHERE [t0].[CustomerID] = [t1].[CustomerID] ) AS [OrderCount] FROM [dbo].[Customers] AS [t0]
2.三向聯接(There way join):
此示例顯式聯接三個表並分別從每個表投影出結果:
var q = from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID into ords join e in db.Employees on c.City equals e.City into emps select new { c.ContactName, ords = ords.Count(), emps = emps.Count() };
生成SQL語句為:
SELECT [t0].[ContactName], ( SELECT COUNT(*) FROM [dbo].[Orders] AS [t1] WHERE [t0].[CustomerID] = [t1].[CustomerID] ) AS [ords], ( SELECT COUNT(*) FROM [dbo].[Employees] AS [t2] WHERE [t0].[City] = [t2].[City] ) AS [emps] FROM [dbo].[Customers] AS [t0]
3.左外部聯接(Left Outer Join):
此示例說明如何通過使用 此示例說明如何通過使用DefaultIfEmpty() 獲取左外部聯接。在雇員沒有訂單時,DefaultIfEmpty()方法返回null:
var q = from e in db.Employees join o in db.Orders on e equals o.Employee into ords from o in ords.DefaultIfEmpty() select new { e.FirstName, e.LastName, Order = o };
說明:以Employees左表,Orders右表,Orders 表中為空時,用null值填充。Join的結果重命名ords,使用DefaultIfEmpty()函數對其再次查詢。其最後的結果中有個Order,因為from o in ords.DefaultIfEmpty() 是對ords組再一次遍歷,所以,最後結果中的Order並不是一個集合。但是,如果沒有from o in ords.DefaultIfEmpty() 這句,最後的select語句寫成select new { e.FirstName, e.LastName, Order = ords }的話,那麼Order就是一個集合。
4.投影的Let賦值(Projected let assignment):
說明:let語句是重命名。let位於第一個from和select語句之間。
這個例子從聯接投影出最終“Let”表達式:
var q = from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID into ords let z = c.City + c.Country from o in ords select new { c.ContactName, o.OrderID, z };
5.組合鍵(Composite Key):
這個例子顯示帶有組合鍵的聯接:
var q = from o in db.Orders from p in db.Products join d in db.OrderDetails on new { o.OrderID, p.ProductID } equals new { d.OrderID, d.ProductID } into details from d in details select new { o.OrderID, p.ProductID, d.UnitPrice };
說明:使用三個表,並且用匿名類來說明:使用三個表,並且用匿名類來表示它們之間的關係。它們之間的關係不能用一個鍵描述清楚,所以用匿名類,來表示組合鍵。還有一種是兩個表之間是用組合鍵表示關係的,不需要使用匿名類。
6.可為null/不可為null的鍵關係(Nullable/Nonnullable Key Relationship):
這個實例顯示如何構造一側可為 null 而另一側不可為 null 的聯接:
var q = from o in db.Orders join e in db.Employees on o.EmployeeID equals (int?)e.EmployeeID into emps from e in emps select new { o.OrderID, e.FirstName };
LINQ to SQL語句(5)之Order By
適用場景:對查詢出的語句進行排序,比如按時間排序等等。
說明:按指定表達式對集合排序;延遲,:按指定表達式對集合排序;延遲,預設是升序,加上descending表示降序,對應的擴展方法是OrderBy和OrderByDescending
1.簡單形式
這個例子使用 orderby 按雇用日期對雇員進行排序:
var q = from e in db.Employees orderby e.HireDate select e;
說明:預設為升序
2.帶條件形式
註意:Where和Order By的順序並不重要。而在T-SQL中,Where和Order By有嚴格的位置限制。
var q = from o in db.Orders where o.ShipCity == "London" orderby o.Freight select o;
語句描述:使用where和orderby按運費進行排序。
3.降序排序
var q = from p in db.Products orderby p.UnitPrice descending select p;
4.ThenBy
語句描述:使用複合的 orderby 對客戶進行排序,進行排序:
var q = from c in db.Customers orderby c.City, c.ContactName select c;
說明:按多個表達式進行排序,例如先按City排序,當City相同時,按ContactName排序。這一句用Lambda表達式像這樣寫:
var q = .OrderBy(c => c.City) .ThenBy(c => c.ContactName).ToList();
在T-SQL中沒有ThenBy語句,其依然翻譯為OrderBy,所以也可以用下麵語句來表達:
var q = db.Customers .OrderBy(c => c.ContactName) .OrderBy(c => c.City).ToList();
所要註意的是,多個OrderBy操作時,級連方式是按逆序。對於降序的,用相應的降序操作符替換即可。
var q = db.Customers .OrderByDescending(c => c.City) .ThenByDescending(c => c.ContactName).ToList();
需要說明的是,OrderBy操作,不支持按type排序,也不支持匿名類。比如
var q = db.Customers .OrderBy(c => new { c.City, c.ContactName }).ToList();
會被拋出異常。錯誤是前面的操作有匿名類,再跟OrderBy時,比較的是類別。比如
var q = db.Customers .Select(c => new { c.City, c.Address }) .OrderBy(c => c).ToList();
如果你想使用OrderBy(c => c),其前提條件是,前面步驟中,所產生的對象的類別必須為C#語言的基本類型。比如下句,這裡City為string類型。
var q = db.Customers .Select(c => c.City) .OrderBy(c => c).ToList();
5.ThenByDescending
這兩個擴展方式都是用在OrderBy/OrderByDescending之後的,第一個ThenBy/ThenByDescending擴展方法作為第二位排序依據,第二個ThenBy/ThenByDescending則作為第三位排序依據,以此類推
var q = from o in db.Orders where o.EmployeeID == 1 orderby o.ShipCountry, o.Freight descending select o;
語句描述:使用orderby先按發往國家再按運費從高到低的順序對 EmployeeID 1 的訂單進行排序。
6.帶GroupBy形式
var q = from p in db.Products group p by p.CategoryID into g orderby g.Key select new { g.Key, MostExpensiveProducts = from p2 in g where p2.UnitPrice == g.Max(p3 => p3.UnitPrice) select p2 };
語句描述:使用orderby、Max 和 Group By 得出每種類別中單價最高的產品,並按 CategoryID 對這組產品進行排序。
LINQ to SQL語句(6)之Group By/Having
適用場景:分組數據,為我們查找數據縮小範圍。
說明:分配並返回對傳入參數進行分組操作後的可枚舉對象。分組;延遲
1.簡單形式:
var q = from p in db.Products group p by p.CategoryID into g select g;
語句描述:使用Group By按CategoryID劃分產品。
說明:from p in db.Products 表示從表中將產品對象取出來。group p by p.CategoryID into g表示對p按CategoryID欄位歸類。其結果命名為g,一旦重新命名,p的作用域就結束了,所以,最後select時,只能select g。當然,也不必重新命名可以這樣寫:
var q = from p in db.Products group p by p.CategoryID;
我們用示意圖表示:
如果想遍歷某類別中所有記錄,這樣:
foreach (var gp in q) { if (gp.Key == 2) { foreach (var item in gp) { //do something } } }
2.Select匿名類:
var q = from p in db.Products group p by p.CategoryID into g select new { CategoryID = g.Key, g };
說明:在這句LINQ語句中,有2個property:CategoryID和g。這個匿名類,其實質是對返回結果集重新進行了包裝。把g的property封裝成一個完整的分組。如下圖所示:
如果想遍歷某匿名類中所有記錄,要這麼做:
foreach (var gp in q) { if (gp.CategoryID == 2) { foreach (var item in gp.g) { //do something } } }
3.最大值
var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, MaxPrice = g.Max(p => p.UnitPrice) };
語句描述:使用Group By和Max查找每個CategoryID的最高單價。
說明:先按CategoryID歸類,判斷各個分類產品中單價最大的Products。取出CategoryID值,並把UnitPrice值賦給MaxPrice。
4.最小值
var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, MinPrice = g.Min(p => p.UnitPrice) };
語句描述:使用Group By和Min查找每個CategoryID的最低單價。
說明:先按CategoryID歸類,判斷各個分類產品中單價最小的Products。取出CategoryID值,並把UnitPrice值賦給MinPrice。
5.平均值
var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, AveragePrice = g.Average(p => p.UnitPrice) };
語句描述:使用Group By和Average得到每個CategoryID的平均單價。
說明:先按CategoryID歸類,取出CategoryID值和各個分類產品中單價的平均值。
6.求和
var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, TotalPrice = g.Sum(p => p.UnitPrice) };
語句描述:使用Group By和Sum得到每個CategoryID 的單價總計。
說明:先按CategoryID歸類,取出CategoryID值和各個分類產品中單價的總和。
7.計數
var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, NumProducts = g.Count() };
語句描述:使用Group By和Count得到每個CategoryID中產品的數量。
說明:先按CategoryID歸類,取出CategoryID值和各個分類產品的數量。
8.帶條件計數
var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, NumProducts = g.Count(p => p.Discontinued) };
語句描述:使用Group By和Count得到每個CategoryID中斷貨產品的數量。
說明:先按CategoryID歸類,取出CategoryID值和各個分類產品的斷貨數量。 Count函數里,使用了Lambda表達式,Lambda表達式中的p,代表這個組裡的一個元素或對象,即某一個產品。
9.Where限制
var q = from p in db.Products group p by p.CategoryID into g where g.Count() >= 10 select new { g.Key, ProductCount = g.Count() };
語句描述:根據產品的―ID分組,查詢產品數量大於10的ID和產品數量。這個示例在Group By子句後使用Where子句查找所有至少有10種產品的類別。
說明:在翻譯成SQL語句時,在最外層嵌套了Where條件。
10.多列(Multiple Columns)
var categories = from p in db.Products group p by new { p.CategoryID, p.SupplierID } into g select new { g.Key, g };
語句描述:使用Group By按CategoryID和SupplierID將產品分組。
說明:既按產品的分類,又按供應商分類。在by後面,new出來一個匿名類。這裡,Key其實質是一個類的對象,Key包含兩個Property:CategoryID、SupplierID。用g.Key.CategoryID可以遍歷CategoryID的值。
11.表達式(Expression)
var categories = from p in db.Products group p by new { Criterion = p.UnitPrice > 10 } into g select g;
語句描述:使用Group By返回兩個產品序列。第一個序列包含單價大於10的產品。第二個序列包含單價小於或等於10的產品。
說明:按產品單價是否大於10分類。其結果分為兩類,大於的是一類,小於及等於為另一類。
LINQ to SQL語句(7)之Exists/In/Any/All/Contains
適用場景:用於判斷集合中元素,進一步縮小範圍。
Any
說明:用於判斷集合中是否有元素滿足某一條件;不延遲。(若條件為空,則集合只要不為空就返回True,否則為False)。有2種形式,分別為簡單形式和帶條件形式。
1.簡單形式:
僅返回沒有訂單的客戶:
var q = from c in db.Customers where !c.Orders.Any() select c;
生成SQL語句為:
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE NOT (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Orders] AS [t1] WHERE [t1].[CustomerID] = [t0].[CustomerID] ))
2.帶條件形式:
僅返回至少有一種產品斷貨的類別:
var q = from c in db.Categories where c.Products.Any(p => p.Discontinued) select c;
生成SQL語句為:
SELECT [t0].[CategoryID], [t0].[CategoryName], [t0].[Description], [t0].[Picture] FROM [dbo].[Categories] AS [t0] WHERE EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Products] AS [t1] WHERE ([t1].[Discontinued] = 1) AND ([t1].[CategoryID] = [t0].[CategoryID]) )
All
說明:用於判斷集合中所有元素是否都滿足某一條件;不延遲
1.帶條件形式
var q = from c in db.Customers where c.Orders.All(o => o.ShipCity == c.City) select c;
語句描述:這個例子返回所有訂單都運往其所在城市的客戶或未下訂單的客戶。
Contains
說明:用於判斷集合中是否包含有某一元素;不延遲。它是對兩個序列進行連接操作的。
string[] customerID_Set = new string[] { "AROUT", "BOLID", "FISSA" }; var q = ( from o in db.Orders where customerID_Set.Contains(o.CustomerID) select o).ToList();
語句描述:查找"AROUT", "BOLID" 和 "FISSA" 這三個客戶的訂單。先定義了一個數組,在LINQ to SQL中使用Contains,數組中包含了所有的CustomerID,即返回結果中,所有的CustomerID都在這個集合內。也就是in。 你也可以把數組的定義放在LINQ to SQL語句里。比如:
var q = ( from o in db.Orders where ( new string[] { "AROUT", "BOLID", "FISSA" }) .Contains(o.CustomerID) select o).ToList();
Not Contains則取反:
var q = ( from o in db.Orders where !( new string[] { "AROUT", "BOLID", "FISSA" }) .Contains(o.CustomerID) select o).ToList();
1.包含一個對象:
var order = (from o in db.Orders where o.OrderID == 10248 select o).First(); var q = db.Customers.Where(p => p.Orders.Contains(order)).ToList(); foreach (var cust in q) { foreach (var ord in cust.Orders) { //do something } }
語句描述:這個例子使用Contain查找哪個客戶包含OrderID為10248的訂單。
2.包含多個值:
string[] cities = new string[] { "Seattle", "London", "Vancouver", "Paris" }; var q = db.Customers.Where(p=>cities.Contains(p.City)).ToList();
語句描述:這個例子使用Contains查找其所在城市為西雅圖、倫敦、巴黎或溫哥華的客戶。
LINQ to SQL語句(8)之Concat/Union/Intersect/Except
適用場景:對兩個集合的處理,例如追加、合併、取相同項、相交項等等。
Concat(連接)
說明:連接不同的集合,不會自動過濾相同項;延遲。
1.簡單形式:
var q = ( from c in db.Customers select c.Phone ).Concat( from c in db.Customers select c.Fax ).Concat( from e in db.Employees select e.HomePhone );
語句描述:返回所有消費者和雇員的電話和傳真。
2.複合形式:
var q = ( from c in db.Customers select new { Name = c.CompanyName, c.Phone } ).Concat( from e in db.Employees select new { Name = e.FirstName + " " + e.LastName, Phone = e.HomePhone } );
語句描述:返回所有消費者和雇員的姓名和電話。
Union(合併)
說明:連接不同的集合,自動過濾相同項;延遲。即是將兩個集合進行合併操作,過濾相同的項。
var q = ( from c in db.Customers select c.Country ).Union( from e in db.Employees select e.Country );
語句描述:查詢顧客和職員所在的國家。
Intersect(相交)
說明:取相交項;延遲。即是獲取不同集合的相同項(交集)。即先遍歷第一個集合,找出所有唯一的元素,然後遍歷第二個集合,並將每個元素與前面找出的元素作對比,返回所有在兩個集合內都出現的元素。
var q = ( from c in db.Customers select c.Country ).Intersect( from e in db.Employees select e.Country );
語句描述:查詢顧客和職員同在的國家。
Except(與非)
說明:排除相交項;延遲。即是從某集合中刪除與另一個集合中相同的項。先遍歷第一個集合,找出所有唯一的元素,然後再遍歷第二個集合,返回第二個集合中所有未出現在前面所得元素集合中的元素。
var q = ( from c in db.Customers select c.Country ).Except( from e in db.Employees select e.Country );
語句描述:查詢顧客和職員不同的國家。
LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods
適用場景:適量的取出自己想要的數據,不是全部取出,這樣性能有所加強。
Take
說明:獲取集合的前n個元素;延遲。即只返回限定數量的結果集。
var q = ( from e in db.Employees orderby e.HireDate select e) .Take(5);
語句描述:選擇所雇用的前5個雇員。
Skip
說明:跳過集合的前n個元素;延遲。即我們跳過給定的數目返回後面的結果集。
var q = ( from p in db.Products orderby p.UnitPrice descending select p) .Skip(10);
語句描述:選擇10種最貴產品之外的所有產品。
TakeWhile
說明:直到某一條件成立就停止獲取;延遲。即用其條件去依次判斷源序列中的元素,返回符合判斷條件的元素,該判斷操作將在返回false或源序列的末尾結束 。
SkipWhile
說明:直到某一條件成立就停止跳過;延遲。即用其條件去判斷源序列中的元素並且跳過第一個符合判斷條件的元素,一旦判斷返回false,接下來將不再進行判斷並返回剩下的所有元素。
Paging(分頁)操作
適用場景:結合Skip和Take就可實現對數據分頁操作。
1.索引
var q = ( from c in db.Customers orderby c.ContactName select c) .Skip(50) .Take(10);
語句描述:使用Skip和Take運算符進行分頁,跳過前50條記錄,然後返回接下來10條記錄,因此提供顯示Products表第6頁的數據。
2.按唯一鍵排序
var q = ( from p in db.Products where p.ProductID > 50 orderby p.ProductID select p) .Take(10);
語句描述:使用Where子句和Take運算符進行分頁,首先篩選得到僅50 (第5頁最後一個ProductID)以上的ProductID,然後按ProductID排序,最後取前10個結果,因此提供Products表第6頁的數據。請註意,此方法僅適用於按唯一鍵排序的情況。
SqlMethods操作
在LINQ to SQL語句中,為我們提供了SqlMethods操作,進一步為我們提供了方便,例如Like方法用於自定義通配表達式,Equals用於相比較是否相等。
Like
自定義的通配表達式。%表示零長度或任意長度的字元串;_表示一個字元;[]表示在某範圍區間的一個字元;[^]表示不在某範圍區間的一個字元。比如查詢消費者ID以“C”開頭的消費者。
var q = from c in db.Customers where SqlMethods.Like(c.CustomerID, "C%") select c;
比如查詢消費者ID沒有“AXOXT”形式的消費者:
var q = from c in db.Customers where !SqlMethods.Like(c.CustomerID, "A_O_T") select c;
DateDiffDay
說明:在兩個變數之間比較。分別有:DateDiffDay、DateDiffHour、DateDiffMillisecond、DateDiffMinute、DateDiffMonth、DateDiffSecond、DateDiffYear
var q = from o in db.Orders where SqlMethods .DateDiffDay(o.OrderDate, o.ShippedDate) < 10 select o;
語句描述:查詢在創建訂單後的 10 天內已發貨的所有訂單。
已編譯查詢操作(Compiled Query)
說明:在之前我們沒有好的方法對寫出的SQL語句進行編輯重新查詢,現在我們可以這樣做,看下麵一個例子:
//1.創建compiled query NorthwindDataContext db = new NorthwindDataContext(); var fn = CompiledQuery.Compile( (NorthwindDataContext db2, string city) => from c in db2.Customers where c.City == city select c); //2.查詢城市為London的消費者,用LonCusts集合表示,這時可以用數據控制項綁定 var LonCusts = fn(db, "London"); //3.查詢城市為Seattle的消費者 var SeaCusts = fn(db, "Seattle");
語句描述:這個例子創建一個已編譯查詢,然後使用它檢索輸入城市的客戶。
LINQ to SQL語句(10)之Insert
1.簡單形式
說明:new一個對象,使用InsertOnSubmit方法將其加入到對應的集合中,使用SubmitChanges()提交到資料庫。
NorthwindDataContext db = new NorthwindDataContext(); var newCustomer = new Customer { CustomerID = "MCSFT", CompanyName = "Microsoft", ContactName = "John Doe", ContactTitle = "Sales Manager", Address = "1 Microsoft Way", City = "Redmond", Region = "WA", PostalCode = "98052", Country = "USA", Phone = "(425) 555-1234", Fax = null }; db.Customers.InsertOnSubmit(newCustomer); db.SubmitChanges();
語句描述:使用InsertOnSubmit方法將新客戶添加到Customers 表對象。調用SubmitChanges 將此新Customer保存到資料庫。
2.一對多關係
說明:Category與Product是一對多的關係,提交Category(一