动态拼接查询(IQueryable 延迟执行)

有时候需要根据条件动态拼接查询逻辑,IQueryable 支持延迟执行——在调用 ToList()First() 等之前,查询并不会真正发送到数据库。利用这个特性,可以分步构建查询,最终一次性执行。

代码示例

// 初始查询(此时未查库,只是定义查询结构)
var jfx = db.XX.AsQueryable();

// 根据条件动态拼接
if (isjq)
{
    jfx = from j in jfx
          join f in db.FY
          on j.bh equals f.id
          where f.lx == 0
          select j;
}

// 后续继续使用 jfx 作为子表继续查询
var q = from jf in jfx
        // ... 继续 where / join / select
        select jf;

// 直到这里才真正执行 SQL
var result = q.ToList();Code language: JavaScript (javascript)

生成的 SQL(当 isjq = true 时)

SELECT [t0].[...]
FROM [dbo].[XX] AS [t0]
INNER JOIN [dbo].[FY] AS [t1]
ON [t0].[bh] = [t1].[id]
WHERE [t1].[lx] = 0Code language: PHP (php)

不带条件时的 SQL

isjq = false 时,jfx 没有被重新赋值,直接作为 XX 表的查询:

SELECT [t0].[...]
FROM [dbo].[XX] AS [t0]Code language: CSS (css)

常见用法模式

模式一:条件追加 Where

var q = db.Student.AsQueryable();

if (!string.IsNullOrEmpty(keyword))
{
    q = q.Where(s => s.name.Contains(keyword));
}

if (minAge.HasValue)
{
    q = q.Where(s => s.age >= minAge.Value);
}

var result = q.ToList();Code language: JavaScript (javascript)

模式二:条件 Join(你的示例)

var q = db.XX.AsQueryable();

if (isjq)
{
    q = from j in q
        join f in db.FY on j.bh equals f.id
        where f.lx == 0
        select j;
}Code language: JavaScript (javascript)

模式三:条件排序

if (sortBy == "age")
{
    q = q.OrderBy(s => s.age);
}
else
{
    q = q.OrderBy(s => s.name);
}Code language: JavaScript (javascript)

关键要点

要点说明
延迟执行IQueryableToList()/First()/Count()终端方法调用前不查库
链式拼接每次 Where/Join/OrderBy 返回新 IQueryable,需重新赋值
最终合并所有拼接逻辑合并为一条 SQL​ 发给数据库
AsQueryable()Table<T> 显式转为 IQueryable<T>,方便后续赋值
性能比先 ToList() 再在内存中过滤好得多,全程数据库端执行

注意:​ 不要对 IQueryable 调用 ToList() 后再拼接条件,那会把全表数据拉到内存。始终保持 IQueryable 直到最后一步才物化。

发表回复

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