# ZDbUtil **Repository Path**: HW-Commons/ZDbUtil ## Basic Information - **Project Name**: ZDbUtil - **Description**: ZDbUtil是一款基于SQLite的鸿蒙数据库框架 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 6 - **Forks**: 2 - **Created**: 2025-01-10 - **Last Updated**: 2025-08-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: 数据库, Sqlite, 鸿蒙, OpenHarmony, OpenHarmony组件 ## README ## 介绍 ZDbUtil是一款数据库操作工具库 - 通过注解类和字段,与数据库的表进行关联 - 支持状态管理(V1)中被@Observed装饰的类 - 支持状态管理(V2)中被@ObservedV2装饰的类 - 支持存放复杂类型的数据,通过 json 格式进行存储 - 支持一对一/一对多查询 - 数据库升级 ## 链接 ### [源码](https://gitee.com/HW-Commons/ZDbUtil) ### [示例](https://gitee.com/HW-Commons/ZDbUtil/tree/master/entry/src/main/ets) ## 效果图 数据库操作2 ## 下载安装 在每个har/hsp模块中,通过ohpm工具下载安装库: ``` ohpm install @hzw/zdb ``` ## 注解 ### Table - **表** - **参数** - `name`: 表名,默认为类名 ### Column - **列** - **参数**: - `name`: 列名,默认为字段名称 - `type`: 列类型,查看ColumnType - `Integer`: 整型 - `Text`: 文本类型 - `Boolean`: 布尔类型 - `Real`: 浮点类型 - `primaryKey`: 是否主键 - `autoIncrement`: 是否自增 - `notNull`: 是否为空 - `unique`: 是否唯一 ### OneToOne - **联表查询,一对一** - **参数**: - `joinTable`: 关联表的类 - `relatedIdProperty`: 关联id属性名,该属性是主表关联类的字段 ### OneToMany - **一对多,使用方法参考[一对多查询](#一对多查询)** - **参数**: - `placeHolderTable`: 占位类,查询的时候通过include把占位类替换为联动表对应实体类 - `relatedIdProperty`: 关联id属性名,该属性是主表关联类的字段 ### ObjToJson - **以json形式存储复杂对象** - **参数**: - `cls`: 复杂对象的类信息 ## 使用方法 ### 定义实体类 只要添加了`@Table`注解,`@Column`注解 在初始化数据库时,会自动创建表,并添加列。 ```typescript import { Column, ColumnType, ObjToJson, OneToOne, Table } from '@hzw/zdb'; // 作业本 export class StudentHomeworkBook { // 书本名 name?: string } // 父亲 export class StudentFather { // 名字 name?: string // 父亲 @ObjToJson({ cls: StudentFather }) father?: StudentFather | undefined } // 分类 @Table() export class StudentClassify { // id @Column({ type: ColumnType.Integer, primaryKey: true, autoIncrement: true }) id?: number // 名称 @Column({ type: ColumnType.Text }) name?: string // 创建时间 @Column({ type: ColumnType.Integer }) createTime?: number // 更新时间 @Column({ type: ColumnType.Integer }) editTime?: number | undefined } // 学生 @Table() export class StudentInfo { // id @Column({ type: ColumnType.Integer, primaryKey: true, autoIncrement: true }) id?: number | undefined // 标题 @Column({ type: ColumnType.Text }) title?: string | undefined // 创建时间 @Column({ type: ColumnType.Integer }) createTime?: number | undefined // 成绩 @Column({ type: ColumnType.Real }) score?: number | undefined // 是否管理员 @Column({ type: ColumnType.Boolean }) isManager?: boolean | undefined // 分类id @Column({ type: ColumnType.Integer }) classifyId?: number | undefined // 分类 @OneToOne({ joinTable: StudentClassify, relatedIdProperty: "classifyId" }) classify?: StudentClassify | undefined // 名下作业本 @ObjToJson({ cls: StudentHomeworkBook }) homeworkBookList?: StudentHomeworkBook[] | undefined // 父亲 @ObjToJson({ cls: StudentFather }) father?: StudentFather | undefined } ``` ### 初始化数据库并根据被@Table注解的类创建表 ```typescript ZDbUtil.initDatabase({ context: this.context }) ``` ### 查数据 如果查询的数据类型有被@Table注解,则通过这种方式查询数据 更多条件查询查看请查看[SQL查询构建器方法速查表](#SQL查询构建器方法速查表) ```typescript // 查询多条数据 ZDbUtil.querySqlBuilder(StudentClassify) .limitAs(this.pageSize) .offsetAs(this.page * this.pageSize) // ...其他条件查询 .query() .then((data) => { }) ``` ```typescript // 根据 id 查询单条数据 ZDbUtil.querySqlBuilder(StudentInfoV1) .queryOneById(id) .then((data) => { this.item = data; }) ``` 以下是查询构建类核心方法的**功能表格**,包含方法名、功能描述,便于快速查阅和使用: #### SQL查询构建器方法速查表 | 方法名 | 功能描述 | |----------------------------------------|--------------------------------------------------| | `equalTo(field, value)` | 添加 `字段 = 值` 条件 | | `notEqualTo(field, value)` | 添加 `字段 <> 值` 条件 | | `notEqualToWithOrIsNull(field, value)` | 添加 `(字段 <> 值 OR 字段 IS NULL)` 条件(值不等或字段为空) | | `and()` | 添加逻辑与(AND)连接符 | | `or()` | 添加逻辑或(OR)连接符 | | `beginWrap()` | 开始包裹条件(生成左括号 `(`) | | `endWrap()` | 结束包裹条件(生成右括号 `)`) | | `contains(field, value)` | 添加 `字段包含值` 条件(基于 `INSTR` 函数) | | `beginsWith(field, value)` | 添加 `字段以值开头` 条件(`LIKE '值%'`) | | `endsWith(field, value)` | 添加 `字段以值结尾` 条件(`LIKE '%值'`) | | `like(field, value)` | 添加 `字段模糊匹配值` 条件(`LIKE '%值%'`) | | `glob(field, value)` | 添加 `字段按通配符匹配值` 条件(`GLOB` 操作符,区分大小写) | | `notContains(field, value)` | 添加 `字段不包含值` 条件(`INSTR` 结果为 0) | | `notLike(field, value)` | 添加 `字段不模糊匹配值` 条件(`NOT LIKE '%值%'`) | | `greaterThan(field, value)` | 添加 `字段 > 值` 条件 | | `lessThan(field, value)` | 添加 `字段 < 值` 条件 | | `greaterThanOrEqualTo(field, value)` | 添加 `字段 >= 值` 条件 | | `lessThanOrEqualTo(field, value)` | 添加 `字段 <= 值` 条件 | | `between(field, low, high)` | 添加 `字段 BETWEEN 低值 AND 高值` 条件 | | `notBetween(field, low, high)` | 添加 `字段 NOT BETWEEN 低值 AND 高值` 条件 | | `in(field, values)` | 添加 `字段 IN (值列表)` 条件 | | `notIn(field, values)` | 添加 `字段 NOT IN (值列表)` 条件 | | `isNull(field)` | 添加 `字段 IS NULL` 条件 | | `isNotNull(field)` | 添加 `字段 IS NOT NULL` 条件 | | `orderByAsc(field)` | 添加 `ORDER BY 字段 ASC` 排序(升序) | | `orderByDesc(field)` | 添加 `ORDER BY 字段 DESC` 排序(降序) | | `orderByAscCaseStart()` | 在 `ORDER BY` 中使用 `CASE` 自定义排序 | | `orderByAscCaseEnd()` | 添加 ` ELSE xxx END` 条件,用在 orderByAscCaseStart() 后 | | `distinct(values)` | 添加 `DISTINCT` 去重(指定去重字段) | | `limitAs(value)` | 添加 `LIMIT 值` 限制返回行数 | | `offsetAs(rowOffset)` | 添加 `OFFSET 值` 跳过指定行数 | | `groupBy(fields)` | 添加 `GROUP BY 字段` 分组 | | `indexedBy(field)` | 添加 `INDEXED BY 字段` 索引提示(优化查询) | **说明** - 逻辑组合:`and()`/`or()` 需配合 `beginWrap()`/`endWrap()` 使用,或直接链式调用(如 `a.and().b.or().c` 会自动生成 `a AND b OR c`)。 - 调用顺序:`orderByAsc()`/`orderByDesc()`/`limitAs()`/`offsetAs()` 放在其他条件的后面使用 通过此表可快速定位所需方法,结合链式调用实现复杂查询条件的动态拼接。 **示例** - 多个分组排序,使用 `orderByAscCaseStart` 开始分组排序,然后添加条件进行分组,最后使用 `orderByAscCaseEnd` 结束分组排序 ```typescript ZDbUtil.querySqlBuilder(StudentInfoV1) .orderByAscCaseStart() // 先根据isManager进行分组排序 .equalTo("isManager", true) // 管理员分为一组 .orderByAscCaseEnd() // 剩余分为一组 .orderByAscCaseStart() // 再根据score进行分组排序 .greaterThan("grade", 4) // 年级4以上分为一组 .greaterThan("grade", 3) // 年级3以上分为一组 .orderByAscCaseEnd() // 剩余分为一组 .orderByAsc("score") // 组内成绩排序 .query() .then((data) => { this.list = data; }) ``` #### 一对多查询 1. 定义一对多的表关联类的占位类 ```typescript // 学生占位类 export class StudentInfoPlaceholder { } ``` 2. 实体类一对多字段用@OneToMany注解,并传入一个 **占位类** 和 **关联表的相关类字段** ```typescript // 分类 @Table() export class StudentClassify { // 省略... // 该分类下的学员 @OneToMany({ placeHolderTable: StudentInfoPlaceholder, relatedIdProperty: "classifyId" }) user?: StudentInfo[]; } ``` 3. 查询方法调用include,传入 **真正的关联类** ,替换 **占位类** ```typescript ZDbUtil.querySqlBuilder(StudentClassify) // 显式加载一对多的表关联类,只有调用该方法,一对多查询才会生效 .include(StudentInfo, StudentInfoPlaceholder) .query() .then((data) => { this.classifyList = data; }) ``` ### 插入/更新数据 data类型确定,且被@Table注解,直接插入/更新数据 ```typescript ZDbUtil.insertOrReplace(data).then(() => { promptAction.showToast({ message: "添加成功" }); }) ``` data类型是Object,通过传入被@Table注解的类,插入/更新数据 ```typescript // 插入/更新数据 // 第一个参数为插入/更新的数据 // 第二个参数为被@Table注解的类,数据将会被插入/更新到与注解类关联的表中 ZDbUtil.insertOrReplaceByCls(data, StudentClassify).then(() => { promptAction.showToast({ message: "添加成功" }); }) ``` ### 批量插入/更新数据 data类型确定,且被@Table注解,直接插入/更新数据 ```typescript ZDbUtil.batchInsert(data).then(() => { promptAction.showToast({ message: "添加成功" }); }) ``` data类型是Object,通过传入被@Table注解的类,插入/更新数据 ```typescript // 批量插入/更新数据 // 第一个参数为插入/更新的数据 // 第二个参数为被@Table注解的类,数据将会被插入/更新到与注解类关联的表中 ZDbUtil.batchInsertByCls(data, StudentClassify).then(() => { promptAction.showToast({ message: "添加成功" }); }) ``` ### 更新数据 传入被@Table注解的类,条件更新数据 ```typescript // 找出 title = this.updateTitle 的数据,把 score 更新为 this.updateScoreByTitle ZDbUtil.updateSqlBuilder(StudentInfoV1) .set("score", Number(this.updateScoreByTitle)) .equalTo("title", this.updateTitle) .update() .then((num) => { promptAction.showToast({ message: `修改${num}条,返回手动刷新数据` }); }) .catch((err: BusinessError) => { promptAction.showToast({ message: `删除失败:${err}` }); }) ``` 传入被@Table注解的类,根据主键更新数据 ```typescript // 找出主键为 this.updateId 的数据,把 score 更新为 this.updateScoreById ZDbUtil.updateSqlBuilder(StudentInfoV1) .set("score", Number(this.updateScoreById)) .updateOneById(Number(this.updateId)) .then((num) => { promptAction.showToast({ message: `修改${num}条,返回手动刷新数据` }); }) .catch((err: BusinessError) => { promptAction.showToast({ message: `删除失败:${err}` }); }) ``` ### 删除数据 data类型确定,且被@Table注解,直接删除数据 ```typescript ZDbUtil.delete(item).then(() => { promptAction.showToast({ message: "删除成功" }); }) ``` data类型是Object,通过传入被@Table注解的类,删除数据 ```typescript ZDbUtil.deleteByCls(data, StudentInfo).then(() => { promptAction.showToast({ message: "删除成功" }); }) ``` 通过传入被@Table注解的类,删除指定条件的数据 ```typescript // 删除 title = this.deleteTitle 的数据 ZDbUtil.deleteSqlBuilder(StudentInfoV1) .equalTo("title", this.deleteTitle) .delete() .then((num) => { promptAction.showToast({ message: `删除${num}条,返回手动刷新数据` }); }) .catch((err: BusinessError) => { promptAction.showToast({ message: `删除失败:${err}` }); }) ``` 通过传入被@Table注解的类,删除指定id数据 ```typescript // 删除主键为 this.deleteId 的数据 ZDbUtil.deleteSqlBuilder(StudentInfoV1) .deleteOneById(Number(this.deleteId)) .then((num) => { promptAction.showToast({ message: `删除${num}条,返回手动刷新数据` }); }) .catch((err: BusinessError) => { promptAction.showToast({ message: `删除失败:${err}` }); }) ``` ### 清空数据 根据被@Table注解的类,清空与之关联的表的所有数据 ```typescript ZDbUtil.clear(StudentInfo).then(() => { promptAction.showToast({ message: "清空成功" }); }) ``` ### 开启打印sql相关日志 ```typescript ZDbUtil.sqlLogEnable(true) ``` 或初始化数据库方法中 sqlLogEnable 参数设为 true ```typescript ZDbUtil.initDatabase({ // ... sqlLogEnable: true, }) ``` ### 升级数据库版本 自动升级,需要配置 changeByUpdate 参数为 true,以及设置数据库版本 dbVersion ```typescript ZDbUtil.initDatabase({ // ... // 是否升级数据库版修改数据库结构(开启后,如果类修改了,需要升级数据库版本dbVersion) changeByUpdate: true, // 数据库版本 dbVersion: 2, }) ``` 手动升级,需要配置 changeByUpdate 参数为 true,以及设置数据库版本 dbVersion,并配置数据库版本迁移 migrations ```typescript ZDbUtil.initDatabase({ // .. // 是否升级数据库版修改数据库结构(开启后,如果类修改了,需要升级数据库版本dbVersion) changeByUpdate: true, // 数据库版本 dbVersion: 7, // 数据库版本迁移 migrations: [ new Migration(5, 6) .addColumn(StudentInfo, 'isManager2', ColumnType.Text) // 添加列 .delColumn(StudentInfo, 'age'), // 删除列 new Migration(6, 7) .alterColumnType(StudentInfo, 'isManager2', ColumnType.Boolean) // 修改列类型 .alterColumnName(StudentInfo, 'isManager2', 'isManager'), // 修改列名 new Migration(7, 8) .addCustomSql(StudentInfo, 'alter table student_info add column isManager2 text;'),// 自定义sql, ], }) ``` ## 作者其他库 - 鸿蒙ui组件库:https://gitee.com/HW-Commons/ZUtils/tree/master - 验证码输入组件 (CaptchaCode):https://gitee.com/HW-Commons/ZUtils/tree/master/ui/captchaCode - 倒计时组件 (Countdown):https://gitee.com/HW-Commons/ZUtils/tree/master/ui/countdown - 加载等待组件 (Loading):https://gitee.com/HW-Commons/ZUtils/tree/master/ui/loading - 下拉刷新组件 (Refresh):https://gitee.com/HW-Commons/ZUtils/tree/master/ui/refresh - 图片选择组件 (SelectImage):https://gitee.com/HW-Commons/ZUtils/tree/master/ui/selectImage - 鸿蒙数据库工具:https://gitee.com/HW-Commons/ZDbUtil - 鸿蒙JSON/对象转换工具:https://gitee.com/HW-Commons/ZJson ## 联系我们 **欢迎大家提交issue、PR(可以统一收集问题,方便更多人查阅,会第一时间回复处理)** ,或进群交流(+v: _hhbin)。 tab