ORMX的查询构建功能 - 开发日志,查询构建, Where条件, OrderBy排序, GroupBy分组, Join连接, 分页查询 - 学习ORMX的查询构建功能,包括Where条件、OrderBy排序、GroupBy分组、Join连接和分页查询。

您当前正在浏览的是本站SEO版网页

请点击确认

马上提升浏览体验

ORMX的查询构建功能

编程 数据库 阅读:0
2/8/2026 9:13:12 PM

学习ORMX的查询构建功能,包括Where条件、OrderBy排序、GroupBy分组、Join连接和分页查询。 关键字:查询构建, Where条件, OrderBy排序, GroupBy分组, Join连接, 分页查询

查询构建

链式调用原理

ORMX 采用链式继承设计模式,每个查询方法返回不同的接口类型,实现流畅的链式调用。理解这一机制有助于更好地使用 ORMX。

链式调用的工作原理

userTable
    .Where(u => u.Age > 25)      // 返回 IWhere<User>
    .OrderBy(u => u.Name)        // 返回 IOrderBy<User>
    .Limit(10)                   // 返回 ILimit<User>
    .GetList();                  // 返回 List<User>

工作原理:

  • 每个方法(如 WhereOrderBy)返回一个特定的接口类型
  • 返回的接口类型包含下一个可用的方法
  • 所有方法共享同一个 QueryBuilder 实例,累积查询条件
  • 最终调用 GetList()FirstOrDefault() 等方法执行查询

设计优势

  1. 类型安全 - 编译时检查,避免拼写错误
  2. 智能提示 - IDE 会根据当前类型显示可用的方法
  3. 功能分离 - 每个方法专注于单一功能
  4. 易于扩展 - 新增功能只需添加新的接口和实现

常见链式调用顺序

虽然 ORMX 允许灵活的调用顺序,但以下顺序更符合 SQL 逻辑:

Table<T>()
  → Where()          // 筛选条件
  → OrderBy()        // 排序
  → Limit()          // 分页
  → GetList()        // 执行查询

或者:

Table<T>()
  → Where()          // 筛选条件
  → GroupBy()        // 分组
  → Having()         // 分组筛选
  → OrderBy()        // 排序
  → Limit()          // 分页
  → GetList()        // 执行查询

Where 条件查询

基本条件查询

使用 Where 方法添加查询条件:

var userTable = tableManager.Table<User>();

// 查询年龄大于 25 的用户
var users = userTable.Where(u => u.Age > 25).GetList();
Console.WriteLine(<div class="latex">$"年龄大于 25 的用户:{users.Count} 个");

// 查询姓名为"张三"的用户
var user = userTable.Where(u => u.Name == "张三").FirstOrDefault();

支持的比较运算符:

  • == - 等于
  • != - 不等于
  • > - 大于
  • >= - 大于等于
  • < - 小于
  • <= - 小于等于

多条件查询

使用多个 Where 方法或使用逻辑运算符:

// 方法一:链式调用
var users = userTable
    .Where(u => u.Age > 25)
    .Where(u => u.Name == "张三")
    .GetList();

// 方法二:逻辑运算符
var users = userTable.Where(u => u.Age > 25 && u.Name == "张三").GetList();

// 方法三:使用 || 运算符
var users = userTable.Where(u => u.Age > 25 || u.Name == "张三").GetList();

支持的逻辑运算符:

  • && - 逻辑与(AND)
  • || - 逻辑或(OR)
  • ! - 逻辑非(NOT)

Between 范围查询

使用 Between 方法查询指定范围内的数据:

// 查询年龄在 18 到 30 之间的用户
var users = userTable.Between(u => u.Age, 18, 30).GetList();
Console.WriteLine($</div>"年龄在 18-30 之间的用户:{users.Count} 个");

// 查询创建时间在指定日期范围内的用户
var users = userTable
    .Between(u => u.CreatedAt, new DateTime(2023, 1, 1), new DateTime(2023, 12, 31))
    .GetList();

NotBetween 排除范围查询

使用 NotBetween 方法查询指定范围外的数据:

// 查询年龄不在 18 到 30 之间的用户
var users = userTable.NotBetween(u => u.Age, 18, 30).GetList();
Console.WriteLine(<div class="latex">$"年龄不在 18-30 之间的用户:{users.Count} 个");

In 列表查询

使用 In 方法查询在指定列表中的数据:

// 查询 ID 为 1、2、3 的用户
var users = userTable.In(u => u.Id, 1, 2, 3).GetList();
Console.WriteLine($</div>"ID 为 1、2、3 的用户:{users.Count} 个");

// 查询姓名在指定列表中的用户
var names = new string[] { "张三", "李四", "王五" };
var users = userTable.In(u => u.Name, names).GetList();

NotIn 排除列表查询

使用 NotIn 方法查询不在指定列表中的数据:

// 查询 ID 不为 1、2、3 的用户
var users = userTable.NotIn(u => u.Id, 1, 2, 3).GetList();
Console.WriteLine(<div class="latex">$"ID 不为 1、2、3 的用户:{users.Count} 个");

Like 模糊查询

使用 Like 方法进行模糊查询:

// 查询姓名以"张"开头的用户
var users = userTable.Like(u => u.Name, "张%").GetList();
Console.WriteLine($</div>"姓名以张开头的用户:{users.Count} 个");

// 查询姓名包含"三"的用户
var users = userTable.Like(u => u.Name, "%三%").GetList();
Console.WriteLine(<div class="latex">$"姓名包含三的用户:{users.Count} 个");

// 查询姓名以"三"结尾的用户
var users = userTable.Like(u => u.Name, "%三").GetList();
Console.WriteLine($</div>"姓名以三结尾的用户:{users.Count} 个");

// 查询邮箱以"@example.com"结尾的用户
var users = userTable.Like(u => u.Email, "%@example.com").GetList();

通配符说明:

  • % - 匹配任意长度的任意字符
  • _ - 匹配单个任意字符

NotLike 排除模糊查询

使用 NotLike 方法排除模糊查询的结果:

// 查询姓名不以"张"开头的用户
var users = userTable.NotLike(u => u.Name, "张%").GetList();
Console.WriteLine(<div class="latex">$"姓名不以张开头的用户:{users.Count} 个");

组合高级条件

可以将高级条件与基本条件组合使用:

// 查询年龄在 18-30 之间且姓名以"张"开头的用户
var users = userTable
    .Between(u => u.Age, 18, 30)
    .Like(u => u.Name, "张%")
    .GetList();

// 查询年龄在 18-30 之间且 ID 不为 1、2、3 的用户
var users = userTable
    .Between(u => u.Age, 18, 30)
    .NotIn(u => u.Id, 1, 2, 3)
    .GetList();

// 查询姓名包含"三"且邮箱以"@example.com"结尾的用户
var users = userTable
    .Like(u => u.Name, "%三%")
    .Like(u => u.Email, "%@example.com")
    .GetList();

字符串操作(Where 表达式)

除了使用 Like 方法外,还可以在 Where 表达式中使用字符串方法:

// LIKE 查询(包含)- 等价于 WHERE Name LIKE '%张%'
var users = userTable.Where(u => u.Name.Contains("张")).GetList();

// LIKE 查询(开头)- 等价于 WHERE Name LIKE '张%'
var users = userTable.Where(u => u.Name.StartsWith("张")).GetList();

// LIKE 查询(结尾)- 等价于 WHERE Name LIKE '%三'
var users = userTable.Where(u => u.Name.EndsWith("三")).GetList();

// 等于查询
var users = userTable.Where(u => u.Name == "张三").GetList();

// 不等于查询
var users = userTable.Where(u => u.Name != "张三").GetList();

WhereComplex 复杂条件组合

WhereComplex 方法允许在一个表达式中组合多个 Where 条件,支持复杂的逻辑运算(AND、OR、括号)。这对于构建复杂的查询条件非常有用。

####.1 基本用法

// 组合 Where 和 Where 条件
var users = userTable
    .WhereComplex(w => w.Where(u => u.Id == 1) && w.Where(u => u.Name == "张三"))
    .GetList();
// 生成 SQL: SELECT * FROM User WHERE ("Id" = @p1) AND ("Name" = @p0)

####.2 组合 Where 和高级条件

// 组合 Where 和 Between
var users = userTable
    .WhereComplex(w => w.Where(u => u.Name == "张三") && w.Between(u => u.Age, 18, 30))
    .GetList();
// 生成 SQL: SELECT * FROM User WHERE ("Name" = @p2) AND ("Age" BETWEEN @p0 AND @p1)

// 组合 Where 和 In
var users = userTable
    .WhereComplex(w => w.Where(u => u.Name == "张三") && w.In(u => u.Id, 1, 2, 3))
    .GetList();
// 生成 SQL: SELECT * FROM User WHERE ("Name" = @p3) AND ("Id" IN (@p0, @p1, @p2))

// 组合 Where 和 Like
var users = userTable
    .WhereComplex(w => w.Where(u => u.Age > 18) && w.Like(u => u.Name, "张%"))
    .GetList();
// 生成 SQL: SELECT * FROM User WHERE ("Age" > @p1) AND ("Name" LIKE @p0)

####.3 使用 OR 逻辑

// 使用 OR 逻辑
var users = userTable
    .WhereComplex(w => w.Where(u => u.Id == 1) || w.Where(u => u.Id == 2))
    .GetList();
// 生成 SQL: SELECT * FROM User WHERE "Id" = @p0 OR "Id" = @p1

####.4 复杂嵌套条件

// 复杂嵌套条件(使用括号)
var users = userTable
    .WhereComplex(w => 
        (w.Where(u => u.Name == "张三") && w.Between(u => u.Age, 18, 30)) || 
        (w.Where(u => u.Name == "李四") && w.Between(u => u.Age, 25, 40))
    )
    .GetList();
// 生成 SQL: SELECT * FROM User WHERE 
// (("Name" = @p4) AND ("Age" BETWEEN @p5 AND @p1)) OR 
// (("Name" = @p0) AND ("Age" BETWEEN @p2 AND @p3))

####.5 多条件组合

// 多个条件的复杂组合
var users = userTable
    .WhereComplex(w => 
        (w.Where(u => u.Name == "张三") && w.Between(u => u.Age, 18, 30) && w.In(u => u.Id, 1, 2, 3)) || 
        (w.Where(u => u.Name == "李四") && w.NotBetween(u => u.Age, 40, 60) && w.Like(u => u.Email, "%company.com")) ||
        (w.Where(u => u.Age > 18) && w.NotIn(u => u.Id, 10, 11, 12) && w.NotLike(u => u.Name, "Test%"))
    )
    .GetList();

WhereComplex 的优势:

  • 支持复杂的逻辑运算(AND、OR、括号)
  • 可以在一个表达式中组合多个 Where 条件
  • 生成的 SQL 更清晰,可读性更好
  • 适合构建复杂的查询条件

多表连接

ORMX 支持 JOIN 操作,可以连接多个表进行查询。关于 JOIN 操作的详细用法,请参考连表查询

// 内连接
var result = userTable
    .InnerJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

// 左连接
var result = userTable
    .LeftJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

// 右连接
var result = userTable
    .RightJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

// 全连接
var result = userTable
    .FullJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

关于 JOIN 操作的详细说明,请查阅连表查询

OrderBy 排序

单字段排序

// 升序排序
var users = userTable.OrderBy(u => u.Age).GetList();

// 降序排序
var users = userTable.OrderByDesc(u => u.Age).GetList();

多字段排序

// 先按年龄升序,再按姓名降序
var users = userTable
    .OrderBy(u => u.Age)
    .OrderByDesc(u => u.Name)
    .GetList();

多表排序

在 Join 查询中排序:

var result = userTable
    .Join<Order, User, Order, object>(
        (u, o) => u.Id == o.UserId,
        (u, o) => new { u.Name, o.Amount }
    )
    .OrderBy(x => x.Name)
    .GetList();

GroupBy 分组

单字段分组

// 按年龄分组
var groups = userTable
    .GroupBy(u => u.Age)
    .Max(u => u.Age, "MaxAge")
    .Min(u => u.Age, "MinAge")
    .Count(u => u.Id, "Count")
    .GetList<AgeGroupStats>();

多字段分组

// 按年龄和姓名分组
var groups = userTable
    .GroupBy(u => new { u.Age, u.Name })
    .Max(u => u.Age, "MaxAge")
    .Count(u => u.Id, "Count")
    .GetList<AgeNameGroupStats>();

关于聚合函数的详细用法,请查阅聚合函数

Having 分组后筛选

// 分组后筛选数量大于 1 的组
var groups = userTable
    .GroupBy(u => u.Age)
    .Having(u => u.Age > 25)
    .Max(u => u.Age, "MaxAge")
    .Count(u => u.Id, "Count")
    .GetList<AgeGroupStats>();

Join 连接查询

ORMX 支持多种 JOIN 操作,包括 INNER JOIN、LEFT JOIN、RIGHT JOIN 和 FULL JOIN。关于 JOIN 操作的详细说明,请查阅连表查询

内连接(INNER JOIN)

var result = userTable
    .InnerJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

左连接(LEFT JOIN)

var result = userTable
    .LeftJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

右连接(RIGHT JOIN)

var result = userTable
    .RightJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

全连接(FULL JOIN)

var result = userTable
    .FullJoin<Order>((u, o) => u.Id == o.UserId)
    .GetList();

无限级联 Join

var result = userTable
    .InnerJoin<Order>((u, o) => u.Id == o.UserId)
    .InnerJoin<Product>((o, p) => o.Id == p.OrderId)
    .GetList();

关于 JOIN 操作的详细说明,请查阅连表查询

Select 选择列

选择单个列

// 选择姓名列
var names = userTable.Select(u => u.Name).GetList();

选择多个列

// 选择姓名和邮箱列
var users = userTable.Select(u => new { u.Name, u.Email }).GetList();

Limit/Offset 分页

Limit 限制结果数量

// 只返回前 10 条记录
var users = userTable.Limit(10).GetList();

Offset 跳过记录

// 跳过前 10 条记录,返回剩余记录
var users = userTable.Offset(10).GetList();

分页查询

// 方法一:使用 Offset + Limit
var pageSize = 10;
var pageNumber = 2;
var users = userTable
    .Offset((pageNumber - 1) * pageSize)
    .Limit(pageSize)
    .GetList();

// 方法二:使用 Page 方法(更简便)
var users = userTable.Page(pageNumber, pageSize).GetList();

Page 方法优势:

  • 语法更简洁,一行代码完成分页
  • 自动计算 OFFSET 值
  • 推荐使用 Page 方法进行分页查询

链式查询组合

ORMX 支持链式调用,可以组合多个查询方法:

var users = userTable
    .Where(u => u.Age > 25)
    .Where(u => u.Name.Contains("张"))
    .OrderByDesc(u => u.Age)
    .Limit(10)
    .GetList();

查询执行

GetList

将查询结果转换为列表:

var users = userTable.Where(u => u.Age > 25).GetList();

FirstOrDefault

返回第一个元素,如果没有则返回 null:

var user = userTable.Where(u => u.Name == "张三").FirstOrDefault();

GetOne

返回单个元素,如果没有则返回 null:

var user = userTable.Where(u => u.Id == 1).GetOne();

完整示例

using System;
using JCode.ORMX.Attributes;
using JCode.ORMX.DbProvider;
using JCode.ORMX.Core;
using Microsoft.Data.Sqlite;

[Table(Name = "Users")]
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    public string Name { get; set; }
    
    public string Email { get; set; }
    
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
        var tableManager = provider.GetTableManager();
        
        // 创建表
        tableManager.Create<User>();
        
        // 插入数据
        var userTable = tableManager.Table<User>();
        userTable.Insert(new User { Name = "张三", Email = "zhangsan@example.com", Age = 25 });
        userTable.Insert(new User { Name = "李四", Email = "lisi@example.com", Age = 30 });
        
        // 查询数据
        var users = userTable.Where(u => u.Age > 25).GetList();
        
        foreach (var user in users)
        {
            Console.WriteLine($</div>"{user.Name}, {user.Age}岁");
        }
    }
}

EasyQuery 动态查询

什么是 EasyQuery

EasyQuery 是 ORMX 框架中提供的轻量级、灵活的查询条件构建器。它允许你通过简单的字符串表达式或强类型的 Lambda 表达式来构建复杂的数据库查询条件,非常适合用于处理前端传递的动态查询参数(如 RESTful API 的查询字符串)。

核心特性:

  • 字符串表达式解析 - 支持将类似 [gt,18][like,*John*] 的字符串解析为 SQL 查询条件
  • 强类型 Lambda 支持 - 支持使用 x => x.Age > 18 的方式设置条件,提供编译时类型检查
  • 复杂逻辑分组 - 支持通过 SetGroup 方法对条件进行 AND / OR 的复杂组合
  • 排序支持 - 内置对 ASCDESC 排序的解析

基础用法

方式一:直接实例化并设置条件

var query = new EasyQuery<User>();
query.Set(new Dictionary<string, string>
{
    { "Name", "John" },
    { "Age", "18" }
});

var users = userTable.EasyWhere(query).GetList();

方式二:通过字典初始化(推荐用于 API 开发)

// 常用于接收前端 JSON 或 QueryString
var conditions = new Dictionary<string, string>
{
    { "Age", "[GT,18]" },
    { "Status", "1" }
};
var query = new EasyQuery<User>(conditions);

var users = userTable.EasyWhere(query).GetList();

方式三:强类型 Lambda 设置(最推荐)

var query = new EasyQuery<User>();

// 使用 Equals 方法传递表达式字符串,提供编译时类型检查
query.Set(x => x.Name.Equals("[LIKE,*John*]"));
query.Set(x => x.Age.Equals("[GT,18]"));

var users = userTable.EasyWhere(query).GetList();

表达式语法

EasyQuery 支持丰富的字符串表达式语法,基本格式为:[操作符,值]

比较操作符

操作符 简写 说明 示例 对应 SQL
EQ E, = 等于 [EQ,18]18 = 18
NEQ NE, != 不等于 [NEQ,18]!18 != 18
GT > 大于 [GT,18]>18 > 18
GTE GE, >= 大于等于 [GTE,18]>=18 >= 18
LT < 小于 [LT,18]<18 < 18
LTE LE, <= 小于等于 [LTE,18]<=18 <= 18

字符串操作符

操作符 说明 示例 对应 SQL
LIKE 模糊匹配(使用 * 代替 % [LIKE,*John*] LIKE '%John%'
NOTLIKE 不匹配 [NOTLIKE,*John*] NOT LIKE '%John%'
CONTAINS 包含 [CONTAINS,John] LIKE '%John%'
STARTSWITH 以...开始 [STARTSWITH,John] LIKE 'John%'
ENDSWITH 以...结束 [ENDSWITH,John] LIKE '%John'

集合与范围操作符

操作符 说明 示例 对应 SQL
IN 在集合中(使用 \| 分隔) [IN,1\|2\|3] IN (1, 2, 3)
NOTIN 不在集合中 [NOTIN,1\|2\|3] NOT IN (1, 2, 3)
BETWEEN 在范围内 [BETWEEN,18\|30] BETWEEN 18 AND 30
NOTBETWEEN 不在范围内 [NOTBETWEEN,18\|30] NOT BETWEEN 18 AND 30

分组逻辑

使用 SetGroup 方法定义分组之间的逻辑关系:

var query = new EasyQuery<User>();

// 设置分组条件
query.Set(new Dictionary<string, string>
{
    // G1 组:名字包含 John 且 年龄大于 18
    { "Name", "G1[LIKE,*John*]" },
    { "Age", "G1[GT,18]" },
    
    // G2 组:邮箱包含 @example.com
    { "Email", "G2[LIKE,*@example.com*]" }
});

// 设置分组逻辑:(G1 的条件) OR (G2 的条件)
// 即:(Name LIKE '%John%' AND Age > 18) OR (Email LIKE '%@example.com%')
query.SetGroup("G1|G2");

var users = userTable.EasyWhere(query).GetList();

组合语法说明:

  • | 表示 OR (或)
  • & 表示 AND (与)
  • 支持使用括号 () 改变优先级,例如:(G1|G2)&G3

实际应用示例

示例 1:RESTful API 中的动态查询

[HttpGet("users")]
public IActionResult GetUsers([FromQuery] Dictionary<string, string> filters)
{
    var query = new EasyQuery<User>(filters);
    var users = _tableManager.Table<User>()
        .EasyWhere(query)
        .GetList();
    return Ok(users);
}

// 前端请求:GET /api/users?Age=[GT,18]&Name=[LIKE,*John*]

示例 2:复杂条件查询

var query = new EasyQuery<User>();
query.Set(x => x.Age.Equals("[GTE,18]"));
query.Set(x => x.Status.Equals("1"));
query.Set(x => x.Email.Equals("[LIKE,*@example.com*]"));

// 按年龄降序排序
query.Set(x => x.Age, "[DESC]");

var users = userTable.EasyWhere(query).GetList();

示例 3:分组查询(高级)

var query = new EasyQuery<User>();
query.Set(new Dictionary<string, string>
{
    { "Age", "G1[GT,18]" },           // G1: 年龄>18
    { "Status", "G1[EQ,1]" },         // G1: 状态=1
    { "Name", "G2[LIKE,*张*]" },      // G2: 名字包含"张"
});

// 查询逻辑:(年龄>18 AND 状态=1) OR (名字包含"张")
query.SetGroup("G1|G2");

var users = userTable.EasyWhere(query).GetList();

EasyQuery 的优势

  1. 动态查询 - 非常适合处理前端传递的查询参数
  2. 类型安全 - 通过 Lambda 表达式提供编译时类型检查
  3. 灵活组合 - 支持复杂的逻辑分组和条件组合
  4. 易于测试 - 可以独立测试查询条件
  5. API 友好 - 天然适合 RESTful API 的查询字符串解析

注意事项

  1. 字符串格式 - 使用 * 代替 % 进行模糊匹配
  2. 分组命名 - 分组名称(如 G1、G2)可以自定义,但要保持一致
  3. 空值处理 - 空字符串会被忽略,不会生成查询条件
  4. 异常处理 - 如果传入了不存在的属性名或无法转换的数据类型,会抛出异常,建议在 API 层进行统一捕获和处理

总结

本章介绍了 ORMX 框架的查询构建功能,包括 Where 条件查询、OrderBy 排序、GroupBy 分组、Join 连接和分页查询。ORMX 提供了丰富的查询方法,支持链式调用,可以灵活组合各种查询条件。WhereComplex 方法允许构建复杂的逻辑条件,支持 AND、OR 和括号运算。合理使用查询构建功能,可以高效地检索和过滤数据。

扩展思考

在复杂查询场景下,如何优化查询性能?是否需要使用索引、查询计划分析等技术?对于大数据量的查询,如何避免内存溢出和性能问题?在分布式系统中,如何实现跨节点的查询和聚合?这些问题值得在深入使用 ORMX 后进一步思考。