linq中的子查询

将 IQueryable 对象当作”表”进行二次查询

核心概念

在 LINQ 中,IQueryable<T> 对象可以像数据库表一样被再次查询。你可以对它继续执行 where 过滤、join 连接等操作,LINQ to SQL 会将所有操作合并为一条 SQL 语句发送给数据库执行,而不是先查出来再在内存中过滤。


完整示例代码

using (var db = new DataClasses1DataContext())
{
    // 第一步:表连接,得到一个 IQueryable 查询对象(尚未执行)
    var query = from s in db.Student
                join p in db.Product
                on s.ID equals p.Sid
                select new
                {
                    s.ID,
                    s.Name,
                    s.ClassID,
                    Dname = p.Name,
                    p.Price
                };

    // 第二步:对 query 再次执行 where 过滤
    var query2 = from q in query
                 where q.ID == 1
                 select q;
    var result = query2.ToList();

    // 第三步:对 query 再次执行 join 连接(与 Classx 表关联)
    var query3 = from q in query
                 join c in db.Classx
                 on q.ClassID equals c.ID
                 select new { q, c };
    var result2 = query3.ToList();
}Code language: JavaScript (javascript)

执行逻辑示意

┌──────────────────────────────────────────────────────────────────┐
│  query(连接后的中间结果集,类型为 IQueryable<匿名类型>)          │
│  相当于一张"虚拟表",包含学生 + 产品的联合字段                     │
├──────────────────────────────────────────────────────────────────┤
│  可以像操作实体表一样对它进行:                                    │
│  ✦ where 过滤    ✦ join 连接    ✦ orderby 排序                   │
│  ✦ group by 分组 ✦ select 投影                                   │
└──────────────────────────────────────────────────────────────────┘Code language: HTML, XML (xml)
步骤变量操作说明
queryStudentProduct内连接,投影出 IDNameClassIDDnamePrice
query2query + where ID == 1基于虚拟表再过滤,SQL 合并为一条语句
query3queryClassx基于虚拟表再与班级表连接,形成三层关联

关键要点

  • 延迟执行(Deferred Execution):queryquery2query3 在定义时都不会立即查询数据库,只有在调用 .ToList() / .First() / .Count()终端操作符时才会执行
  • SQL 合并机制:​ LINQ to SQL 会将多层查询组合成单条 SQL。以 query2 为例,最终生成的 SQL 等价于:SELECT s.ID, s.Name, s.ClassID, p.Name AS Dname, p.Price FROM Student s INNER JOIN Product p ON s.ID = p.Sid WHERE s.ID = 1
  • 复用性:​ 同一个 query 可以被多个后续查询复用,各自追加不同条件,互不干扰

常见使用场景

场景做法
公共查询条件复用先定义基础 IQueryable,多处复用并追加不同 where
动态条件拼接根据业务判断逐步追加 Where()OrderBy()
多表级联先连接 A、B 表,再基于结果连接 C、D 表

注意事项

IQueryable vs IEnumerable​ 如果在中间调用了 .AsEnumerable().ToList(),后续操作将在内存中执行而非翻译成 SQL,可能导致全表加载,需谨慎使用。

匿名类型的局限:query 中使用了匿名类型(new { s.ID, s.Name, ... }),只能在当前方法内使用,无法跨方法传递。如需跨方法复用,建议定义具名 DTO 类

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注