LINQ TO SQL 大全

来源:http://www.cnblogs.com/chenwolong/archive/2016/12/09/lts.html
-Advertisement-
Play Games

最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。 十年河東十年河西,莫欺少年窮 學無止境,精益求精 最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。 十年河東十年河西,莫欺少年窮 學無止境,精益求精 最近悟出來一 ...


最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。

十年河東十年河西,莫欺少年窮

學無止境,精益求精

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(一

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • IIS7.0 IIS7.0主要引入了WAS(Windows Process Activation,不同於6.0中的Web Admin Service),分擔了原來w3svc的部分功能,同時為IIS7.0提供了非HTTP協協議的支持,通過適配器介面(Listener Adapter Interface ...
  • Ext.NET 4.1 系統框架的搭建(後臺) 附源碼 代碼運行環境:.net 4.5 VS2013 (代碼可直接編譯運行) 預覽圖: 分析圖: 上面系統的構建包括三塊區域:North、West和Center: North負責顯示系統信息,包括系統圖片、當前時間、登錄信息、退出登錄等功能。 West ...
  • 這幾天上網翻閱了不少前輩們的關於iis和asp.net運行原理的博客,學的有點零零散散,花了好長時間做了一個小結(雖然文字不多,但也花了不少時間呢),鄙人不才,難免有理解不道的地方,還望前輩們不吝賜教。 這篇博客主要是描述asp.net程式在iis6.0上的一個執行過程。 執行過程圖: 組件描述 H ...
  • 前言 在ASP.NET Core中引入了DI,並且通過構造函數註入參數,控制器中會大量使用DI註入各種的配置參數,如果配置註入的參數比較多,而且各個控制器需要的配置參數都基本一樣的話,那麼不斷重覆的複製黏貼代碼提供相應的構造函數,效率低效也,因此使用T4模板生成控制器的構造函數 ,這也得益於C#對分 ...
  • 什麼是發佈訂閱 發佈訂閱是一種設計模式定義了一對多的依賴關係,讓多個訂閱者對象同時監聽某一個主題對象。這個主題對象在自身狀態變化時,會通知所有的訂閱者對象,使他們能夠自動更新自己的狀態。 為了描述這種模式,我們將會構建一個簡單的日誌系統。它包括兩個程式——第一個程式負責發送日誌消息,第二個程式負責獲... ...
  • 對於到多數開發者,都會忽略或者不知道 Action 沒有任何 HTTP 的聲明屬性,Web Api 怎樣處理? 對於初學者,還是需要瞭解 NonActionAttribute ...
  • 上一篇,介紹了怎麼導出Excel文件,這篇文章介紹在ASP.NET MVC中使用水晶報表。 項目源碼下載:https://github.com/caofangsheng93/CrystalReportInMac 前提條件:你需要有VS,SQL Server 當然最重要的就是安裝Crystal Rep ...
  • WPF 控制項像 HTML 的 class 屬性一樣同時應用多個樣式,<Button Style="{wms:MultiStyle btn btn-default btn-lg}" Content="Large button" /> ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...