这是一个sqlite的增强工具,无需编写sql代码,通过继承BaseMapper类,一行搞定增删改查,为简化开发、提高效率而生。(类似Mybatis-plus)
v1.0.6存在bug,已删除。可使用v1.0.5替代或者采用2024-12-21发布的最新版本v1.0.8
ohpm i rdbplus
OpenHarmony ohpm
环境配置等更多内容,请参考如何安装 OpenHarmony ohpm 包
https://gitee.com/yongoe/RdbPlus/tree/main/entry/src/main/ets
https://github.com/yongoe1024/RdbPlus/tree/main/entry/src/main/ets
函数名 | 介绍 |
---|---|
count | 查询符合条件的记录总数 |
getList | 查询符合条件的记录 |
getPage | 分页查询符合条件的记录 |
getObject | 查询符合条件的记录,返回对象数组 |
getObjectBySql | 输入SQL查询符合条件的记录,返回对象数组 |
getById | 根据 ID 查询 |
insert | 插入一条记录 |
updateById | 根据 ID 更新数据 |
update | 更新符合条件的记录 |
deleteById | 根据 ID 删除 |
delete | 删除符合条件的记录 |
- 首先引入ohpm依赖:
ohpm i rdbplus
- 创建一个数据库表对应的实体类,推荐ts格式,比如
Employee.ts
- 创建一个mapper类,比如
EmpMapper.ets
- 直接在页面中
new出EmpMapper
,就可以调用增删改查的方法,无需编写SQL代码
推荐在src/main/ets/entity
路径中,创建ts文件Employee.ts
export class Employee {
id: number
name: string
constructor() {
}
}
推荐在src/main/ets/mapper
路径中,创建ets文件EmpMapper.ets
- 首先创建
EmpMapper类
,然后继承BaseMapper
,传入泛型Employee
- 创建构造函数,调用super方法。
第一个参数是一个对象
,包含表名
、主键字段名
两项内容
第二个参数是回调函数
:(res: relationalStore.ResultSet)=> T
,返回一个泛型对象,本意是为了从ResultSet中得到一行数据
第三个参数是可选值
,传入relationalStore.StoreConfig
,比如数据库名、安全级别等。默认库名demo.db
import { Employee } from '../entity/Employee'
import { relationalStore } from '@kit.ArkData'
import { BaseMapper } from 'rdbplus'
const getRow = (res: relationalStore.ResultSet) => {
const emp = new Employee()
emp.id = res.getLong(res.getColumnIndex('id'))
emp.name = res.getString(res.getColumnIndex('name'))
return emp
}
export class EmpMapper extends BaseMapper<Employee> {
constructor() {
super(
{ tableName: 't_emp', primaryKey: 'id' },
getRow,
// 可选参数
{ name: 'demo.db', securityLevel: relationalStore.SecurityLevel.S1 }
)
}
}
import { EmpMapper } from '../mapper/EmpMapper'
@Entry
@Component
struct Index {
empMapper = new EmpMapper()
build()
{
Button('查询全部数据').onClick(() => {
// 查询全部
let list:1 Employee[] = await this.empMapper.getList(new Wapper())
// 条件查询
let list2: Employee[] = await this.empMapper.getList(new Wapper().eq('name', '李四'))
// 统计总数
const num:number = await this.empMapper.count(new Wapper())
})
}
}
- 调用
EmpMapper
对象中的getConnection()
方法,得到一个Connection
对象 Connection
有两个函数:execDML
、execDQL
execDML
是数据操纵函数,执行创建、添加、修改 语句
execDQL
是数据查询函数,执行查询语句
在EmpMapper.ets
中,添加一个函数createTable
,用来创建表
export class EmpMapper extends BaseMapper<Employee> {
...其余省略
...
async createTable() {
const db = await this.getConnection()
await db.execDML(`DROP TABLE IF EXISTS t_emp ;`)
await db.execDML(
`create table if not exists "t_emp" (
id integer primary key autoincrement,
name varchar(20)
)`)
await db.execDML(`INSERT INTO t_emp (id,name) VALUES (null, ? );`, ['111'])
await db.close()
}
}
以下代码示例的前提条件是:已经实现了一个mapper类,例如EmpMapper
查询符合条件的记录总数
返回值: 符合条件的记录总数。
入参 | 说明 |
---|---|
wapper: Wapper | 查询条件 |
返回值 | 说明 |
---|---|
number | 统计值 |
// 统计总数
const num:number = await this.empMapper.count(new Wapper())
查询符合条件的记录
返回值: 查询结果,一个对象类型的数组
入参 | 说明 |
---|---|
wapper: Wapper | 搜索条件 |
返回值 | 说明 |
---|---|
AnyObject[] | 对象数组 |
// 查询name等于111的数据
const objList = await this.empMapper.getObject(new Wapper().eq('name', '111'))
通过SQL,查询符合条件的记录
返回值: 查询结果,一个对象类型的数组
入参 | 说明 |
---|---|
sql: string | sql语句 |
params: relationalStore.ValueType[] | 占位符参数 |
返回值 | 说明 |
---|---|
AnyObject[] | 对象数组 |
// 统计行数
const res = await this.mapper.getObjectBySql('select count(*) from t_emp', [])
查询符合条件的记录
返回值: 查询结果,泛型T的数组
入参 | 说明 |
---|---|
wapper: Wapper | 搜索条件 |
返回值 | 说明 |
---|---|
T[] | 泛型T的数组 |
// 查询name等于111的数据,返回数组
const list = await this.empMapper.getList(new Wapper().eq('name', '111'))
分页查询符合条件的记录
返回值:分页查询结果,包含记录列表和总记录数
入参 | 说明 |
---|---|
wapper: Wapper | 搜索条件 |
返回值 | 说明 |
---|---|
Page | 分页查询结果 |
Page | 说明 |
---|---|
total | 总数 |
current | 当前页 |
size | 每页数量 |
record | 结果集 |
// 查询第一页的数据,返回Page对象
const page = await this.empMapper.getPage(1, 10)
// 总数
const total = page.total
// 当前页
const current = page.current
// 每页条数
const size = page.size
// 结果集
const record = page.record
根据主键ID查询
返回值: 查询结果,可能是undefined或泛型T的对象
入参 | 说明 |
---|---|
id: ValueType | 主键值 |
返回值 | 说明 |
---|---|
T 或 undefined | 存在返回结果,不存在返回undefined |
// 查询主键ID等于14的数据
this.empMapper.getById(14)
插入一条记录
返回值:void,失败则抛出异常
注:若插入的某个字段为空,可以设置为 undefined或null
入参 | 说明 |
---|---|
obj: T | 一个泛型T的对象 |
返回值 | 说明 |
---|---|
void | 执行失败抛出异常 |
const emp = new Employee()
emp.name = '新添加的'
// 如果是自增,id可以不用赋值
this.empMapper.insert(emp)
根据 ID ,更新符合条件的记录
返回值:void,失败则抛出异常
注:不想更新的字段必须设置为undefined
,其他值包括null,都会更新到数据库
入参 | 说明 |
---|---|
obj: T | 一个泛型T的对象,主键不能为空 |
返回值 | 说明 |
---|---|
void | 执行失败抛出异常 |
const emp = new Employee()
emp.id = 20
emp.name = '张三'
// 根据主键id修改
this.empMapper.updateById(emp)
通过指定条件更新数据
返回值:void,失败则抛出异常
入参 | 说明 |
---|---|
wapper: Wapper | 更新条件 |
返回值 | 说明 |
---|---|
void | 执行失败抛出异常 |
// 将name等于张三的数据,改为name等于李四
this.empMapper.update(new Wapper().set('name', '李四').eq('name', '张三'))
根据 ID ,删除数据
返回值:void,失败则抛出异常
入参 | 说明 |
---|---|
id: ValueType | 主键值 |
返回值 | 说明 |
---|---|
void | 执行失败抛出异常 |
// 删除主键ID等于5的数据
this.empMapper.deleteById(5)
通过指定条件删除数据
返回值:void,失败则抛出异常
入参 | 说明 |
---|---|
wapper: Wapper | 删除条件 |
返回值 | 说明 |
---|---|
void | 执行失败抛出异常 |
// 删除name等于111的数据
this.empMapper.delete(new Wapper().eq('name', '111'))
获取一个数据库的连接对象Connection
,可以直接进行SQL语句的调用
参考上面的建表、连接查询等复杂SQl,采用手写SQL方法
获取一个新的数据库连接
入参 | 说明 |
---|---|
config: relationalStore.StoreConfig | 数据库配置 |
返回值 | 说明 |
---|---|
Connection | Connection对象 |
execDML
是数据操纵函数(DML),执行创建、添加、修改语句
入参 | 说明 |
---|---|
sql: string | SQL语句 |
params | 数组,SQL语句中参数的值。该值与sql参数语句中的? 占位符相对应 |
返回值 | 说明 |
---|---|
void | 执行失败抛出异常 |
execDQL
是数据查询函数,执行查询语句
入参 | 说明 |
---|---|
sql: string | SQL语句 |
params | 数组,SQL语句中参数的值。该值与sql参数语句中的? 占位符相对应 |
返回值 | 说明 |
---|---|
relationalStore.ResultSet | 返回ResultSet |
开启事务
提交事务
回滚事务
关闭当前的Connection连接
在update语句中,用于指定要修改的列及其新值
// 更新`name`等于`张三`的数据,将`name`值更改为`李四`
new Wapper()
.set('name', '李四')
.eq('name', '张三')
等于
// 查询`name`等于`王二`,并且`age`为`18`的数据
new Wapper().eq('name', '王二').eq('age', 18)
不等于
// 查询`name`不等于`王二`的数据
new Wapper().notEq('name', '王二')
小于
// 查询`age`小于`50`的数据
new Wapper().lt('age', 50)
小于等于
// 查询`age`小于等于`50`的数据
new Wapper().lte('age', 50)
大于
// 查询`age`大于`50`的数据
new Wapper().gt('age', 50)
大于等于
// 查询`age`大于等于`50`的数据
new Wapper().gte('age', 50)
设置单个字段的值,在给定的集合中
// 查询`age`在`18、19、20`之中的数据
new Wapper().in('age', [18, 19, 20])
设置单个字段的值,不在给定的集合中
// 查询`age`不在`18、19、20`之中的数据
new Wapper().notIn('age', [18, 19, 20])
设置单个字段的 BETWEEN 条件
// 查询 age 在 18-60之间的数据
new Wapper().between('age', 18, 60)
设置单个字段的 NOT BETWEEN 条件
// 查询 age 不在 18-60之间的数据
new Wapper().notBetween('age', 18, 60)
单个字段的模糊匹配条件
// 匹配 `name` 的第一个字是`张`的数据
new Wapper().like('name', '张%')
单个字段的非模糊匹配条件
// 匹配 `name` 的第一个字,不是`张`的数据
new Wapper().notLike('name', '张%')
单个字段为null
// 查询 `title` 等于null的数据
new Wapper().isNull('title')
单个字段不为null
// 查询 `title` 不等于null的数据
new Wapper().isNotNull('title')
将查询结果根据某字段进行升序排序,可以多次调用,按顺序拼接order内容
// 将查询结果根据id升序排列
new Wapper().orderByAsc('id')
将查询结果根据某字段进行降序排序,可以多次调用,按顺序拼接order内容
// 将查询结果根据id降序排列
new Wapper().orderByDesc('id')
设置查询结果的分组条件。通过指定一个或多个字段
// 依次根据id、name进行分组
new Wapper().groupBy('id', 'name')
生成的sql
SELECT * FROM user GROUP BY id, name
设置 HAVING 子句,过滤分组后的结果。通常与 GROUP BY 一起使用,用于对分组后的数据进行条件筛选
// 根据name分组,过滤分组条件是name不等于张三
new Wapper().groupBy('name').having(`name != '张三'`)
生成的sql
SELECT * FROM user GROUP BY name HAVING name != '张三'
用于在查询条件中添加 OR 逻辑。通过调用 or 方法,可以改变后续查询条件的连接方式,从默认的 AND 连接变为 OR 连接
new Wapper().eq('name', '111')
.or(new Wapper().eq('name', '222').eq('age', 18))
生成SQL为
name = '111' or ( name = '222' and age=18 )
用于在查询条件中添加 AND 逻辑。通过调用 and 方法,可以创建 AND 嵌套条件,即在一个 AND 逻辑块中包含多个查询条件
new Wapper()
.eq('name', '111')
.and(new Wapper().notEq('name', '222'))
生成SQL为
name = '111' and ( name != '222' )
默认查询为: select *
调用select函数,将默认的 *
更改为指定内容
注:若添加了额外内容,例如聚合函数、字段别名,建议使用getObject
方法,将结果从对象中取出(getObjectBySql也可以)
//指定字段
new Wapper().select('id,name,age')
//使用函数
new Wapper().select('count(*),sum(age)')
//字段别名
new Wapper().select('age as nianling')
参考如下示例
import { Employee } from '../entity/Employee'
import { relationalStore } from '@kit.ArkData'
import { BaseMapper, MapperParam } from 'rdbplus'
// 实现一个 getRow
const getRow = (res: relationalStore.ResultSet) => {
const emp = new Employee()
emp.id = res.getLong(res.getColumnIndex('id'))
emp.name = res.getString(res.getColumnIndex('name'))
return emp
}
export class EmpMapper extends BaseMapper<Employee> {
// 构造函数,仅接收参数,将参数传给super
private constructor(config: relationalStore.StoreConfig) {
super({ tableName: 't_emp', primaryKey: 'id' }, getRow, config)
}
// 手动 new出EmpMapper
// 数据库1
static getDemo1DB(): EmpMapper {
return new EmpMapper(
{
name: 'Demo1DB.db',
securityLevel: relationalStore.SecurityLevel.S1
}
)
}
// 数据库2
static getDemo2DB(): EmpMapper {
return new EmpMapper(
{
name: 'Demo2DB.db',
securityLevel: relationalStore.SecurityLevel.S1
}
)
}
}
参考如下代码
import { Employee } from '../entity/Employee'
import { EmpMapper } from '../mapper/EmpMapper'
@Entry
@Component
struct Index {
empMapper = new EmpMapper()
build() {
Row() {
Button('事务成功').onClick(async (event: ClickEvent) => {
// 获取一个db连接
const db = await this.empMapper.getConnection()
try {
//开启事务
db.beginTransaction()
const emp = new Employee()
emp.name = '事务'
// 将 db 传进去,保持所有操作在同一连接上
this.empMapper.insert(emp, db)
//提交事务
db.commit()
} catch (e) {
// 回滚
db.rollBack()
} finally {
// 关闭连接
db.close()
}
})
Button('事务失败').onClick(async (event: ClickEvent) => {
// 获取一个db连接
const db = await this.empMapper.getConnection()
try {
db.beginTransaction()
const emp = new Employee()
emp.name = '事务失败'
// 将 db 传进去,保持所有操作在同一连接上
this.empMapper.insert(emp, db)
// 抛出异常,回滚事务
throw new Error()
//提交事务
db.commit()
} catch (e) {
// 回滚
db.rollBack()
} finally {
// 关闭连接
db.close()
}
})
}
}
}
使用过程中发现任何问题都可以提 Issue
,也欢迎您发 PR
https://gitee.com/yongoe/RdbPlus
https://github.com/yongoe1024/RdbPlus (以github为主)
本项目基于 MIT License