1. Linq to Sql的困惑:当ORM遇上复杂查询
第一次接触Linq to Sql时,那种在C#代码里直接写查询语句的体验确实令人惊艳。但当我试图用它在实际项目中替换传统SQL时,却发现这个看似完美的ORM工具藏着不少"暗坑"。最典型的就是那个N+1查询问题——明明代码只请求了订单数据,背后的SQL却疯狂执行了上百次客户信息查询,性能直接跌入谷底。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础篇:Linq to Sql的核心工作机制
2.1 从表达式树到SQL的魔法转换
当你写下db.Orders.Where(o => o.CustomerID == 123)时,编译器并没有立即执行这段逻辑,而是将其转换为表达式树。这个数据结构在运行时被Linq to Sql提供程序解析,最终生成如下SQL:
sql复制SELECT [t0].[OrderID], [t0].[CustomerID], ...
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[CustomerID] = @p0
这种转换机制带来了强类型检查的优势,但也埋下了第一个隐患:不是所有C#表达式都能完美对应SQL语法。比如尝试在Where条件里调用自定义方法时,运行时就会抛出NotSupportedException。
2.2 延迟加载的双刃剑
默认情况下,关联实体(如Order.Customer)只有在首次访问时才会触发查询。这个设计本意是好的,但在遍历集合时就变成了性能杀手:
csharp复制var orders = db.Orders.Take(100).ToList();
foreach(var order in orders) {
Console.WriteLine(order.Customer.Name); // 每循环一次就执行一次SQL查询
}
解决方案是使用DataLoadOptions.LoadWith预先加载:
csharp复制var options = new DataLoadOptions();
options.LoadWith<Order>(o => o.Customer);
db.LoadOptions = options;
