# 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)
## 效果图
## 下载安装
在每个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)。
