27 RdbPredicates 条件查询详解:EqualTo、OrderBy、组合条件
2026/7/11 9:37:43 网站建设 项目流程

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

等值条件
equalTo / notEqualTo

范围条件
greaterThan / lessThan / between

模糊条件
like / glob

空值条件
isNull / isNotNull

排序分组
orderByAsc / orderByDesc / groupBy

分页限制
limit / offset

组合条件
and / or / beginWrap / endWrap

一、RdbPredicates 基础

1.1 创建和基本用法

RdbPredicates的构造函数接受一个参数——表名,表示该谓词适用于哪张表:

importrelationalStorefrom'@ohos.data.relationalStore'// 创建 predicates:指定表名constpredicates=newrelationalStore.RdbPredicates('handwriting')

1.2 完整查询模式

conststore=DatabaseService.getInstance().getStore()constpredicates=newrelationalStore.RdbPredicates(TABLE)// ... 添加查询条件 ...constrs=awaitstore.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 ?// INpredicates.in('source',['camera','gallery'])// SQL 等价:WHERE source IN (?, ?)

提示:所有值都是参数化绑定(?占位符),不存在 SQL 注入风险。

三、链式调用

3.1 连续的链式调用

// ArchiveDao.listByUserconstpredicates=newrelationalStore.RdbPredicates(TABLE).equalTo('user_id',userId).orderByDesc('last_record_at')// SQL 等价:WHERE user_id = ? ORDER BY last_record_at DESC

3.2 分步链式调用

// HandwritingDao.listUnclassifiedconstpredicates=newrelationalStore.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 NULLconstpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.beginWrap()predicates.equalTo('archive_id',0)// 条件 Apredicates.or()// ORpredicates.isNull('archive_id')// 条件 Bpredicates.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连接:

constpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('archive_id',archiveId)// 默认 ANDpredicates.orderByDesc('created_at')// SQL 等价:WHERE archive_id = ? ORDER BY created_at DESC// (实际上只有 1 个 WHERE 条件 + 1 个 ORDER BY)

4.3 嵌套条件

// 复杂场景示例constpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('user_id',userId)// user_id = ?predicates.beginWrap()// (predicates.greaterThan('energy_score',60)// energy_score > ?predicates.or()// ORpredicates.in('source',['camera','handwrite'])// source IN (?, ?)predicates.endWrap()// )// SQL 等价:// WHERE user_id = ?// AND (energy_score > ? OR source IN (?, ?))

五、各 DAO 中的 RdbPredicates 应用汇总

5.1 UserDao

// findByOpenId —— 等值查询 + 单条结果constpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('open_id',openId)// updateName —— 等值条件 + updateconstpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('id',id)awaitstore.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(constidofids){constpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('id',id)awaitstore.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)awaitstore.delete(predicates)

5.4 各 DAO 的 RdbPredicates 使用统计

DAOequalToorderByDescbeginWrap/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:简单条件查询constpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('archive_id',archiveId)predicates.orderByDesc('created_at')awaitstore.query(predicates,COLS)// ✅ 用原始 SQL:聚合统计awaitstore.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)INWHERE field IN (?, ?)
notIn(field, values)NOT INWHERE 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()OROR

提示:项目中主要使用equalToorderByDescbeginWrap/or/endWrap这几种就覆盖了 90% 的查询场景。更复杂的统计查询直接使用原始 SQL。

八、常见问题

8.1 predicates 不能跨表

// ❌ 错误:RdbPredicates 只能作用于一张表constpredicates=newrelationalStore.RdbPredicates('handwriting')// 无法同时查询 report 表的字段// ✅ 正确:分两次查询或使用原始 SQL JOINconsthandwriting=awaitHandwritingDao.findById(id)constreport=awaitReportDao.findByHandwriting(handwriting.id!)

8.2 每次查询创建新的 predicates

// ✅ 正确:每个方法内部创建新的 predicatesstaticasynclistByArchive(archiveId:number):Promise<HandwritingEntity[]>{constpredicates=newrelationalStore.RdbPredicates(TABLE)predicates.equalTo('archive_id',archiveId)// ...}// ❌ 错误:复用 predicates 对象(状态污染)constglobalPredicates=newrelationalStore.RdbPredicates(TABLE)

总结

本文全面解析了鸿蒙 RDB 中RdbPredicates的用法:

  1. 基础用法new RdbPredicates(TABLE)+ 条件方法 +store.query(predicates, COLS)
  2. 常用条件equalToorderByDescisNull覆盖了项目中 90% 的查询场景
  3. 组合条件beginWrap()/or()/endWrap()构建 OR 嵌套
  4. 链式调用:方法链清晰表达查询意图
  5. 与原始 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 写法constpred=newrelationalStore.RdbPredicates('handwriting')pred.equalTo('user_id',userId).orderByDesc('created_at').limit(10)constrs=awaitstore.query(pred,['id','created_at','image_path'])// 原始 SQL 写法constsql=`SELECT id, created_at, image_path FROM handwriting WHERE user_id = ? ORDER BY created_at DESC LIMIT 10`constrs2=awaitstore.querySql(sql,[userId])

两种方式在功能上等效,RdbPredicates 可读性更好,SQL 方式更灵活。

7.2 选择建议

  • 简单 CRUD 操作→ 优先使用 RdbPredicates,代码更安全易读
  • 聚合统计、JOIN 查询→ 使用querySql原始 SQL
  • 动态多条件筛选→ RdbPredicates 链式调用更优雅
  • 复杂报表查询→ SQL 表达力更强,直接写 SQL

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询