LINQ to SQL是.NET平台上一种将关系数据映射为对象模型的ORM技术,它让开发者可以用C#或VB的语法来书写数据库查询。在已建立好DataContext与实体类的前提下,最常用到的操作便是针对单表的简单筛选,以及跨多个表的联接查询。理解这两类查询的写法与背后机制,是掌握LINQ to SQL的关键一步。

一、简单查询的实现方式
简单查询通常指针对单个数据表(对应一个实体类)进行的筛选、投影与排序。在LINQ to SQL里,我们借助System.Linq命名空间下的标准查询运算符,例如Where、Select、OrderBy等来组合查询。这些调用并不会立即执行,而是构建一个表达式树,等到真正遍历结果时才翻译成SQL发往数据库。
例如,有一个Products表映射为Product类,我们要查出单价大于10且按名称排序的商品。下面代码展示了最基本的写法:
using (var db = new NorthwindDataContext())
{
var query = from p in db.Products
where p.UnitPrice > 10
orderby p.ProductName
select p;
foreach (var item in query)
{
Console.WriteLine(item.ProductName + ": " + item.UnitPrice);
}
}
上述查询在遍历时才执行,LINQ to SQL会生成类似SELECT * FROM Products WHERE UnitPrice > @p0 ORDER BY ProductName的T-SQL。需要注意的是,如果只写查询变量而不遍历,数据库不会收到任何请求,这就是延迟执行特性。
除了查询语法,也可以使用方法语法链式调用,两者最终等效。方法语法在动态组合条件时更灵活,比如根据界面勾选动态拼接Where:
var q = db.Products.AsQueryable();
if (minPrice.HasValue)
{
q = q.Where(p => p.UnitPrice >= minPrice.Value);
}
if (!string.IsNullOrEmpty(keyword))
{
q = q.Where(p => p.ProductName.Contains(keyword));
}
简单查询的优点是直观、类型安全,编译期就能发现字段拼写错误。缺点是如果滥用客户端枚举或调用无法翻译的方法,会导致整个查询在内存中执行,失去数据库端筛选的优势。因此写条件时尽量使用可翻译的运算符与函数。
二、多表联接查询
当业务需要同时利用两张及以上表的数据时,就要用到联接查询。LINQ to SQL支持两种主要方式:一是利用实体间定义好的关联(导航属性)直接点出子表;二是使用join关键字显式按键联接,更接近传统SQL的写法。
假设有Orders与Customers两张表,并且Order类里配置了Customer导航属性,那么下面两种写法都能拿到订单及其客户名:
// 方式一:导航属性(隐式联接)
var q1 = from o in db.Orders
select new
{
o.OrderID,
CustomerName = o.Customer.CompanyName
};
// 方式二:显式 join
var q2 = from o in db.Orders
join c in db.Customers on o.CustomerID equals c.CustomerID
select new
{
o.OrderID,
CustomerName = c.CompanyName
};
显式join在语义上更清晰,尤其是多表联接或需要左外联接时。LINQ to SQL会将equals翻译为SQL的ON条件,并生成INNER JOIN。若要左外联接,可以使用DefaultIfEmpty配合分组联接:
var leftJoin = from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into co
from sub in co.DefaultIfEmpty()
select new
{
c.CompanyName,
OrderID = sub == null ? (int?)null : sub.OrderID
};
联接查询能显著减少多次往返数据库的次数,把关联逻辑下推到数据库引擎执行。但要注意,如果导航属性指向的表很大且未加索引,生成的SQL可能较慢。建议在数据库侧为外键建立索引,并在LINQ里只投影需要的字段,避免select *式抓取全部列。
另外,LINQ to SQL的联接不支持SQL里那种任意条件的ON(例如非等值联接),只能使用equals做等值匹配。遇到复杂关联时,可先取子集再用内存联接,或借助视图与存储过程补充。
三、查询翻译与调试建议
无论是简单查询还是联接查询,最终都依赖LINQ to SQL提供程序将表达式树转为T-SQL。开发时若对生成的脚本有疑问,可以通过DataContext.Log属性把SQL输出到控制台或调试窗口:
db.Log = Console.Out;
var list = (from p in db.Products
where p.UnitPrice > 20
join s in db.Suppliers on p.SupplierID equals s.SupplierID
select new { p.ProductName, s.CompanyName }).ToList();
观察日志能快速发现是否产生了不必要的联接、是否把本应在数据库做的过滤挪到了客户端。对于性能敏感模块,建议将关键查询的SQL贴到数据库管理工具中查看执行计划,确认索引用到了。
总结来看,简单查询适合单表筛选与轻量投影,而联接查询通过导航属性或join实现跨表取数。掌握延迟执行、翻译规则和日志手段,便能写出既简洁又高效的LINQ to SQL代码。
LINQ_to_SQL简单查询联接查询修改时间:2026-08-06 22:54:30