在.NET生态中,LINQ(Language Integrated Query)是连接业务逻辑与数据库操作的桥梁。本文将通过10个典型SQL查询案例,结合深度代码注释和性能对比分析,手把手教你从SQL语法无缝过渡到LINQ的声明式编程范式。
第一章:基础查询转换
1.1 SELECT查询转换
SQL版本:
SELECT ProductID, ProductName, Price
FROM Products
WHERE Category = 'Electronics';
LINQ版本:
// 使用查询语法
var query = from p in dbContext.Products
where p.Category == "Electronics"
select new
{
p.ProductID,
p.ProductName,
p.Price
};
// 使用方法语法
var methodQuery = dbContext.Products
.Where(p => p.Category == "Electronics")
.Select(p => new
{
p.ProductID,
p.ProductName,
p.Price
});
// 执行查询(强制执行)
var result = query.ToList(); // ① 强制执行查询
1.2 排序与分页
SQL版本:
SELECT * FROM Orders
ORDER BY OrderDate DESC
LIMIT 10 OFFSET 20;
LINQ版本:
var pagedResult = dbContext.Orders
.OrderByDescending(o => o.OrderDate) // ① 排序
.Skip(20) // ② 跳过前20条
.Take(10) // ③ 取10条
.ToList();
第二章:连接查询(JOIN)
2.1 内连接(INNER JOIN)
SQL版本:
SELECT o.OrderID, p.ProductName, od.Quantity
FROM Orders o
INNER JOIN OrderDetails od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID;
LINQ版本:
var joinedQuery = from o in dbContext.Orders
join od in dbContext.OrderDetails
on o.OrderID equals od.OrderID
join p in dbContext.Products
on od.ProductID equals p.ProductID
select new
{
o.OrderID,
p.ProductName,
od.Quantity
};
2.2 左外连接(LEFT JOIN)
SQL版本:
SELECT u.UserID, u.UserName, o.OrderID
FROM Users u
LEFT JOIN Orders o ON u.UserID = o.UserID;
LINQ版本:
var leftJoinQuery = from u in dbContext.Users
join o in dbContext.Orders
on u.UserID equals o.UserID
into ordersGroup // ① 使用into创建组
from o in ordersGroup.DefaultIfEmpty() // ② 处理空值
select new
{
u.UserID,
u.UserName,
OrderID = o?.OrderID // ③ 安全访问
};
第三章:聚合与分组
3.1 分组统计(GROUP BY)
SQL版本:
SELECT Category, COUNT(*) AS ProductCount
FROM Products
GROUP BY Category
HAVING COUNT(*) > 5;
LINQ版本:
var groupedQuery = from p in dbContext.Products
group p by p.Category into categoryGroup
where categoryGroup.Count() > 5 // ① HAVING条件
select new
{
Category = categoryGroup.Key,
ProductCount = categoryGroup.Count()
};
3.2 聚合函数(MAX, MIN, AVG)
SQL版本:
SELECT MAX(Price) AS MaxPrice,
MIN(Price) AS MinPrice,
AVG(Price) AS AvgPrice
FROM Products;
LINQ版本:
var aggregateResult = new
{
MaxPrice = dbContext.Products.Max(p => p.Price),
MinPrice = dbContext.Products.Min(p => p.Price),
AvgPrice = dbContext.Products.Average(p => p.Price)
};
第四章:子查询与存在性检查
4.1 子查询(Subquery)
SQL版本:
SELECT * FROM Orders
WHERE OrderID IN (SELECT OrderID FROM OrderDetails WHERE Quantity > 10);
LINQ版本:
var subQuery = dbContext.OrderDetails
.Where(od => od.Quantity > 10)
.Select(od => od.OrderID);
var result = dbContext.Orders
.Where(o => subQuery.Contains(o.OrderID)) // ① 包含子查询
.ToList();
4.2 存在性检查(EXISTS)
SQL版本:
SELECT * FROM Categories
WHERE EXISTS (SELECT 1 FROM Products
WHERE Products.CategoryID = Categories.CategoryID);
LINQ版本:
var existsQuery = dbContext.Categories
.Where(c => dbContext.Products
.Any(p => p.CategoryID == c.CategoryID)) // ① Any实现EXISTS
.ToList();
第五章:复杂查询模式
5.1 多条件动态查询
SQL版本:
SELECT * FROM Employees
WHERE (Department = 'Sales' OR Department = 'Marketing')
AND HireDate BETWEEN '2020-01-01' AND '2023-12-31';
LINQ版本:
var dynamicQuery = dbContext.Employees
.Where(e => new[] { "Sales", "Marketing" }.Contains(e.Department) // ① IN条件
&& e.HireDate >= new DateTime(2020, 1, 1)
&& e.HireDate <= new DateTime(2023, 12, 31));
5.2 跨数据库关联(CROSS JOIN)
SQL版本:
SELECT c.CategoryName, p.ProductName
FROM Categories c
CROSS JOIN Products p
WHERE c.CategoryID = p.CategoryID;
LINQ版本:
var crossJoinQuery = from c in dbContext.Categories
from p in dbContext.Products // ① 无条件连接
where c.CategoryID == p.CategoryID
select new { c.CategoryName, p.ProductName };
第六章:性能与优化
6.1 延迟执行(Lazy Execution)
var query = dbContext.Products.Where(p => p.Price > 100); // ① 未执行
query = query.OrderBy(p => p.Name); // ② 构建查询表达式树
var result = query.ToList(); // ③ 触发数据库查询
6.2 即时执行(Eager Loading)
// 强制即时执行
var cachedData = dbContext.Orders
.Include(o => o.Customer) // ① 预加载关联实体
.ToArray(); // ② 触发立即查询
第七章:高级技巧
7.1 原生SQL与LINQ混合使用
var sqlQuery = dbContext.Database.SqlQuery<Product>(
"SELECT * FROM Products WHERE Price > @0", 200);
var linqQuery = dbContext.Products
.Where(p => p.Price > 200); // ① 两种方式对比
7.2 动态查询构建
var query = dbContext.Products.AsQueryable();
if (!string.IsNullOrEmpty(searchTerm))
{
query = query.Where(p => p.Name.Contains(searchTerm));
}
if (minPrice.HasValue)
{
query = query.Where(p => p.Price >= minPrice.Value);
}
var result = query.ToList();
第八章:常见错误与调试技巧
8.1 转义字符问题
// 错误写法:直接拼接字符串
var query = dbContext.Products.Where(p => p.Name == "O'Reilly"); // ① 报错
// 正确写法:使用参数化查询
var safeQuery = dbContext.Products.Where(p => p.Name == "O'Reilly");
8.2 调试查询语句
// 使用日志记录查看生成的SQL
using (var dbContext = new MyDbContext())
{
dbContext.Database.Log = Console.WriteLine; // ① 输出SQL语句
var result = dbContext.Products.ToList();
}
第九章:LINQ to SQL vs Entity Framework
9.1 数据库映射差异
// LINQ to SQL映射
[Table(Name = "dbo.Products")]
public class Product
{
[Column(IsPrimaryKey = true)]
public int ProductID { get; set; }
}
// Entity Framework映射
public class Product
{
[Key]
public int ProductID { get; set; }
}
9.2 查询优化对比
// EF Core的Include优化
var orders = dbContext.Orders
.Include(o => o.Customer)
.ThenInclude(c => c.Addresses)
.ToList();
// LINQ to SQL的LoadWith
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Order>(o => o.Customer);
dbContext.LoadOptions = dlo;
第十章:未来趋势与扩展
10.1 C# 12的LINQ增强
// 预计特性:管道表达式增强
var result = dbContext.Products
| where p => p.Price > 100
| select p => p.Name
| toList();
10.2 异步查询优化
// 异步执行
var asyncResult = await dbContext.Products
.Where(p => p.Category == "Electronics")
.ToListAsync();
结语:从SQL到LINQ的思维跃迁
通过本文的10个核心案例,开发者可以掌握:
- 语法映射:将传统SQL思维转化为LINQ的声明式语法
- 性能优化:理解延迟执行与表达式树的底层机制
- 复杂场景:处理多表关联、动态查询等高级需求
- 工具链:结合EF Core、LINQPad等工具提升开发效率