首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

深入掌握 LINQ to SQL 查詢語法:從基礎 SELECT 到進階聯集操作

     編輯:關於.NET

前言

LINQ to SQL 作為 .NET 框架中操作關聯式資料庫的核心 ORM 技術,其查詢語法將 C# 語言與 SQL 完美融合。本文透過 Northwind 範例資料庫,系統性整理從基本投影、條件篩選、排序分頁,到群組彙總、集合運算(Union/Intersect/Except)、子查詢與 Join 等實戰場景,並對照生成的 T-SQL,助你精準掌握 LINQ 查詢的寫法與效能特徵。

一、基本投影與匿名型別建構

1.1 簡單欄位選取

var q = from c in ctx.Customers
        select new { 公司名 = c.CompanyName, 地址 = c.Address };

對應 SQL:SELECT [CompanyName], [Address] FROM [Customers]

1.2 運算式與巢狀匿名型別

var q = from emp in ctx.Employees
        select new {
            姓名 = emp.LastName + emp.FirstName,
            雇用年 = emp.HireDate.Value.Year
        };

LINQ 會自動轉換為 DATEPART(Year, HireDate)。

1.3 巢狀物件投影

var q = from c in ctx.Customers
        select new {
            ID = c.CustomerID,
            聯繫資訊 = new { 職位 = c.ContactTitle, 聯繫人 = c.ContactName }
        };

雖然 C# 寫成巢狀,產出的 SQL 仍為扁平化欄位,這點需注意。

二、條件篩選

2.1 三元運算子對應 CASE WHEN

var q = from o in ctx.Orders
        select new {
            訂單號 = o.OrderID,
            是否超重 = o.Freight > 100 ? "是" : "否"
        };

轉譯為參數化 CASE WHEN Freight > @p0 THEN @p1 ELSE @p2 END,防止 SQL 注入。

2.2 多條件與導航屬性計數

var q = from c in ctx.Customers
        where c.Country == "France" && c.Orders.Count > 5
        select new { 國家 = c.Country, 城市 = c.City, 訂單數 = c.Orders.Count };

子查詢會重複出現於 WHERE 與 SELECT,建議若效能敏感可改用 GroupJoin 或預先載入。

三、排序與分頁

3.1 多欄位混合排序

var q = from emp in ctx.Employees
        where emp.Employees.Count == 0
        orderby emp.HireDate.Value.Year descending, emp.FirstName ascending
        select new { 雇用年 = emp.HireDate.Value.Year, 名 = emp.FirstName };

3.2 Skip/Take 實作分頁

var page2 = (from c in ctx.Customers select c).Skip(10).Take(10);

SQL Server 2005+ 產生 ROW_NUMBER() OVER (ORDER BY ...) 視窗函數,效能優於舊版 TOP 子查詢寫法。

四、群組彙總

4.1 單一欄位分組 + Having 篩選

var q = from c in ctx.Customers
        group c by c.Country into g
        where g.Count() > 5
        orderby g.Count() descending
        select new { 國家 = g.Key, 顧客數 = g.Count() };

4.2 多欄位匿名型別分組

var q = from c in ctx.Customers
        group c by new { c.City, c.Country } into g
        orderby g.Key.Country, g.Key.City
        select new { 國家 = g.Key.Country, 城市 = g.Key.City };

4.3 依運算式結果分組

var q = from o in ctx.Orders
        group o by new { 條件 = o.Freight > 100 } into g
        select new {
            數量 = g.Count(),
            是否超重 = g.Key.條件 ? "是" : "否"
        };

此技巧可將任意邏輯轉為分組鍵,極具彈性。

五、集合運算

運算子SQL 對應去重
UnionUNION是
ConcatUNION ALL否
IntersectINTERSECT是
ExceptEXCEPT是

範例:(from c where c.City.Contains("A") select c).Union(from c where c.ContactName.StartsWith("A") select c).OrderBy(c => c.ContactName)

六、子查詢與 IN 操作

6.1 子查詢模擬 EXISTS

var q = from c in ctx.Customers
        where (from o in ctx.Orders
               group o by o.CustomerID into g
               where g.Count() > 5 select g.Key).Contains(c.CustomerID)
        select c;

轉譯為 WHERE EXISTS (SELECT ... GROUP BY CustomerID HAVING COUNT(*) > 5)。

6.2 陣列 Contains 對應 IN

var cities = new[] { "Brandenburg", "Cowes", "Stavern" };
var q = from c in ctx.Customers where cities.Contains(c.City) select c;

自動參數化為 WHERE City IN (@p0, @p1, @p2)。

七、Join 操作

7.1 內部聯結

var q = from p in ctx.Products
        join c in ctx.Categories on p.CategoryID equals c.CategoryID
        select p.ProductName;

7.2 左外部聯結

var q = from p in ctx.Products
        join c in ctx.Categories on p.CategoryID equals c.CategoryID into gj
        from x in gj.DefaultIfEmpty()
        select p.ProductName;

into gj ... DefaultIfEmpty() 是關鍵模式,產生 LEFT OUTER JOIN。

八、效能與最佳實務提醒

  • 延遲執行:查詢變數建立時不會打資料庫,直到列舉(foreach、ToList、Count 等)才發送 SQL。
  • 參數化:所有常值自動參數化,安全且利用查詢計畫快取。
  • N+1 問題:導航屬性(如 c.Orders.Count)若在迴圈中存取,會產生大量查詢;請善用 DataLoadOptions.LoadWith 預先載入。
  • 複雜查詢改用 Stored Procedure:LINQ to SQL 支援 ExecuteQuery 與 ExecuteCommand 直接呼叫 SP,兼顧效能與維護性。

結語

掌握 LINQ to SQL 查詢語法,不僅能以強型別、IntelliSense 輔助撰寫資料存取邏輯,更能透過對照生成的 T-SQL 深入理解 ORM 行為。實務上建議:「簡單查詢用 LINQ,複雜報表用 SP,效能關鍵處用 DataLoadOptions 或原生 SQL」,三者互補,打造健壯且可維護的資料層。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved