27 RdbPredicates 条件查询详解:EqualTo、OrderBy、组合条件
27 RdbPredicates 条件查询详解:EqualTo、OrderBy、组合条件
前言

图:27 RdbPredicates 条件查询详解:EqualTo、OrderBy、组合条件 运行效果截图(HarmonyOS NEXT)
在鸿蒙 RDB 中,RdbPredicates 是构建数据库查询条件的核心类。它提供了一套链式调用 API,让开发者无需编写原始 SQL 即可完成复杂的条件组合。与直接拼接 SQL 相比,RdbPredicates 更安全、更可读、更易维护。
本文以"鹿鹿·笔迹心理分析"项目中的 UserDao、HandwritingDao、ArchiveDao 等 DAO 代码为例,全面解析 RdbPredicates 的各种条件构建方法。
鸿蒙官方·RdbPredicates 文档:developer.huawei.com
项目源码仓库:harmony-app GitHub

图:RdbPredicates 链式 API 分类——等值、范围、模糊、排序、分页
一、RdbPredicates 基础
1.1 创建和基本用法
RdbPredicates 的构造函数接受一个参数——表名,表示该谓词适用于哪张表:
import relationalStore from '@ohos.data.relationalStore'
// 创建 predicates:指定表名
const predicates = new relationalStore.RdbPredicates('handwriting')
1.2 完整查询模式
const store = DatabaseService.getInstance().getStore()
const predicates = new relationalStore.RdbPredicates(TABLE)
// ... 添加查询条件 ...
const rs = await store.query(predicates, ['col1', 'col2', ...])
二、常用查询条件
2.1 等值查询
// 最简单的等值条件
predicates.equalTo('archive_id', archiveId)
// SQL 等价:WHERE archive_id = ?
predicates.equalTo('open_id', 'local')
// SQL 等价:WHERE open_id = ?
2.2 排序
// 降序排列(最新在前)
predicates.orderByDesc('created_at')
// SQL 等价:ORDER BY created_at DESC
// 升序排列
predicates.orderByAsc('created_at')
// SQL 等价:ORDER BY created_at ASC
// 多字段排序
predicates.orderByDesc('last_record_at')
predicates.orderByDesc('id')
// SQL 等价:ORDER BY last_record_at DESC, id DESC
2.3 区间查询
// 不在 NULL 范围内的值
predicates.isNotNull('archive_id')
// SQL 等价:WHERE archive_id IS NOT NULL
// NULL 值
predicates.isNull('archive_id')
// SQL 等价:WHERE archive_id IS NULL
// 大于
predicates.greaterThan('energy_score', 50)
// SQL 等价:WHERE energy_score > ?
// 小于
predicates.lessThan('word_count', 100)
// SQL 等价:WHERE word_count < ?
// 范围
predicates.between('created_at', startTime, endTime)
// SQL 等价:WHERE created_at BETWEEN ? AND ?
// IN
predicates.in('source', ['camera', 'gallery'])
// SQL 等价:WHERE source IN (?, ?)
提示:所有值都是参数化绑定(
?占位符),不存在 SQL 注入风险。
三、链式调用
3.1 连续的链式调用
// ArchiveDao.listByUser
const predicates = new relationalStore.RdbPredicates(TABLE)
.equalTo('user_id', userId)
.orderByDesc('last_record_at')
// SQL 等价:WHERE user_id = ? ORDER BY last_record_at DESC
3.2 分步链式调用
// HandwritingDao.listUnclassified
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.beginWrap()
predicates.equalTo('archive_id', 0)
predicates.or()
predicates.isNull('archive_id')
predicates.endWrap()
predicates.orderByDesc('created_at')
// SQL 等价:WHERE (archive_id = 0 OR archive_id IS NULL) ORDER BY created_at DESC
四、组合条件:beginWrap / or / endWrap
4.1 OR 组合
// 查询未归类笔迹:archive_id = 0 或 archive_id IS NULL
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.beginWrap()
predicates.equalTo('archive_id', 0) // 条件 A
predicates.or() // OR
predicates.isNull('archive_id') // 条件 B
predicates.endWrap()
predicates.orderByDesc('created_at')
// SQL 等价:
// WHERE (archive_id = 0 OR archive_id IS NULL)
// ORDER BY created_at DESC
4.2 AND 组合(默认行为)
如果不显式添加 or(),多个条件默认以 AND 连接:
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('archive_id', archiveId) // 默认 AND
predicates.orderByDesc('created_at')
// SQL 等价:WHERE archive_id = ? ORDER BY created_at DESC
// (实际上只有 1 个 WHERE 条件 + 1 个 ORDER BY)
4.3 嵌套条件
// 复杂场景示例
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('user_id', userId) // user_id = ?
predicates.beginWrap() // (
predicates.greaterThan('energy_score', 60) // energy_score > ?
predicates.or() // OR
predicates.in('source', ['camera', 'handwrite']) // source IN (?, ?)
predicates.endWrap() // )
// SQL 等价:
// WHERE user_id = ?
// AND (energy_score > ? OR source IN (?, ?))
五、各 DAO 中的 RdbPredicates 应用汇总
5.1 UserDao
// findByOpenId —— 等值查询 + 单条结果
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('open_id', openId)
// updateName —— 等值条件 + update
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('id', id)
await store.update({ name }, predicates)
5.2 HandwritingDao
// findById —— 等值查询
predicates.equalTo('id', id)
// listByArchive —— 等值 + 排序
predicates.equalTo('archive_id', archiveId)
predicates.orderByDesc('created_at')
// listUnclassified —— 组合条件(OR)
predicates.beginWrap()
predicates.equalTo('archive_id', 0)
predicates.or()
predicates.isNull('archive_id')
predicates.endWrap()
predicates.orderByDesc('created_at')
// batchUpdateArchive —— 循环更新
for (const id of ids) {
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('id', id)
await store.update({ archive_id: archiveId }, predicates)
}
5.3 ArchiveDao
// listByUser —— 等值 + 排序
predicates.equalTo('user_id', userId)
predicates.orderByDesc('last_record_at')
// findById —— 等值查询
predicates.equalTo('id', id)
// delete —— 等值条件删除
predicates.equalTo('id', id)
await store.delete(predicates)
5.4 各 DAO 的 RdbPredicates 使用统计
| DAO | equalTo | orderByDesc | beginWrap/or/endWrap | 用途 |
|---|---|---|---|---|
| UserDao | ✅ | ❌ | ❌ | 用户查询 |
| HandwritingDao | ✅ | ✅ | ✅ | 笔迹多条件查询 |
| ArchiveDao | ✅ | ✅ | ❌ | 档案查询 |
| ReportDao | ✅ | ✅ | ❌ | 报告查询 |
| RelationDao | ✅ | ✅ | ❌ | 关系查询 |
六、RdbPredicates vs 原始 SQL
6.1 对比
| 对比维度 | RdbPredicates | 原始 SQL(querySql) |
|---|---|---|
| 类型安全 | ✅ 方法名明确语义 | ❌ 字符串拼接易错 |
| SQL 注入防护 | ✅ 自动参数化绑定 | ❌ 需手动 ? 占位 |
| 可读性 | ✅ 链式调用清晰 | ⚠️ 字符串较长时可读性差 |
| 复杂查询(JOIN) | ❌ 不支持 | ✅ 完全支持 |
| 聚合函数 | ❌ 不支持 | ✅ COUNT / AVG / GROUP BY |
| 参数绑定 | 自动 | 需手动传 bindArgs |
6.2 选择建议
// ✅ 用 RdbPredicates:简单条件查询
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('archive_id', archiveId)
predicates.orderByDesc('created_at')
await store.query(predicates, COLS)
// ✅ 用原始 SQL:聚合统计
await store.querySql(
'SELECT COUNT(*) AS cnt FROM handwriting WHERE archive_id = ?',
[archiveId]
)
七、RdbPredicates 的完整 API
| 方法 | 用途 | SQL 等价 | 项目中是否使用 |
|---|---|---|---|
equalTo(field, value) |
等于 | WHERE field = ? |
✅ |
notEqualTo(field, value) |
不等于 | WHERE field != ? |
❌ |
greaterThan(field, value) |
大于 | WHERE field > ? |
❌ |
lessThan(field, value) |
小于 | WHERE field < ? |
❌ |
between(field, lo, hi) |
范围 | WHERE field BETWEEN ? AND ? |
❌ |
in(field, values) |
IN | WHERE field IN (?, ?) |
❌ |
notIn(field, values) |
NOT IN | WHERE field NOT IN (?, ?) |
❌ |
isNull(field) |
为空 | WHERE field IS NULL |
✅ |
isNotNull(field) |
非空 | WHERE field IS NOT NULL |
❌ |
like(field, pattern) |
模糊 | WHERE field LIKE ? |
❌ |
orderByAsc(field) |
升序 | ORDER BY field ASC |
❌ |
orderByDesc(field) |
降序 | ORDER BY field DESC |
✅ |
limit(count) |
限制行数 | LIMIT ? |
❌(用 querySql 替代) |
beginWrap() |
左括号 | ( |
✅ |
endWrap() |
右括号 | ) |
✅ |
or() |
OR | OR |
✅ |
提示:项目中主要使用
equalTo、orderByDesc、beginWrap/or/endWrap这几种就覆盖了 90% 的查询场景。更复杂的统计查询直接使用原始 SQL。
八、常见问题
8.1 predicates 不能跨表
// ❌ 错误:RdbPredicates 只能作用于一张表
const predicates = new relationalStore.RdbPredicates('handwriting')
// 无法同时查询 report 表的字段
// ✅ 正确:分两次查询或使用原始 SQL JOIN
const handwriting = await HandwritingDao.findById(id)
const report = await ReportDao.findByHandwriting(handwriting.id!)
8.2 每次查询创建新的 predicates
// ✅ 正确:每个方法内部创建新的 predicates
static async listByArchive(archiveId: number): Promise<HandwritingEntity[]> {
const predicates = new relationalStore.RdbPredicates(TABLE)
predicates.equalTo('archive_id', archiveId)
// ...
}
// ❌ 错误:复用 predicates 对象(状态污染)
const globalPredicates = new relationalStore.RdbPredicates(TABLE)
总结
本文全面解析了鸿蒙 RDB 中 RdbPredicates 的用法:
- 基础用法:
new RdbPredicates(TABLE)+ 条件方法 +store.query(predicates, COLS) - 常用条件:
equalTo、orderByDesc、isNull覆盖了项目中 90% 的查询场景 - 组合条件:
beginWrap()/or()/endWrap()构建 OR 嵌套 - 链式调用:方法链清晰表达查询意图
- 与原始 SQL 互补:简单查询用 RdbPredicates,复杂聚合用 querySql
下一篇文章将介绍 ValuesBucket 数据插入——create 方法的 ValuesBucket 构建。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
参考资源:
- RdbPredicates API 参考
- RdbStore.query 方法
- [UserDao 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/features/data/UserDao.ets)
- [HandwritingDao 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/features/data/HandwritingDao.ets)
- [ArchiveDao 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/features/data/ArchiveDao.ets)
- [ReportDao 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/features/data/ReportDao.ets)
- [RelationDao 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/features/data/RelationDao.ets)
- 鸿蒙数据持久化指南
- HarmonyOS 开发文档
七、RdbPredicates 与原始 SQL 对比
对于项目中的查询需求,RdbPredicates 和原始 SQL 各有适用场景:
| 场景 | RdbPredicates | 原始 SQL |
|---|---|---|
| 单表简单查询 | ✅ 推荐,链式可读 | 可用但过于繁琐 |
| 多条件组合 | ✅ and/or 组合 | 可用 |
| 聚合统计(COUNT/SUM) | ❌ 不支持 | ✅ 必须用 SQL |
| 多表 JOIN | ❌ 不支持 | ✅ 必须用 SQL |
| 动态条件构建 | ✅ 链式追加条件 | 需要字符串拼接 |
| SQL 注入安全 | ✅ 自动参数化 | 需要手动参数绑定 |
7.1 等效示例
相同查询的两种写法对比:
// RdbPredicates 写法
const pred = new relationalStore.RdbPredicates('handwriting')
pred.equalTo('user_id', userId)
.orderByDesc('created_at')
.limit(10)
const rs = await store.query(pred, ['id', 'created_at', 'image_path'])
// 原始 SQL 写法
const sql = `SELECT id, created_at, image_path FROM handwriting WHERE user_id = ? ORDER BY created_at DESC LIMIT 10`
const rs2 = await store.querySql(sql, [userId])
两种方式在功能上等效,RdbPredicates 可读性更好,SQL 方式更灵活。
7.2 选择建议
- 简单 CRUD 操作 → 优先使用 RdbPredicates,代码更安全易读
- 聚合统计、JOIN 查询 → 使用
querySql原始 SQL - 动态多条件筛选 → RdbPredicates 链式调用更优雅
- 复杂报表查询 → SQL 表达力更强,直接写 SQL
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
更多推荐

所有评论(0)