三尺非寒 发表于 2024-6-11 11:30:26

基于鸿蒙OS4的关系数据库使用学习——以浅易版备忘录为例

概述

这里是我的项目地址,欢迎大家下载参考~有问题欢迎相互指出,谢谢!!
项目gitee地址
丑化说在前头,这个备忘录真的是十分大略,这一篇的写作目的不是为了能告诉读者备忘录怎么写和怎么美化,而是希望在现有鸿蒙OS4关系型数据库教学还比较少的情况下,官网教学也比较大略,把复杂的数据库设置抽离出来,让大家少走点弯路,让大家能更快的使用关系型数据库实现自己想要的业务目标。
笔者走了许多弯路了呜呜,希望大家多多点赞收藏~~
废话不多说,开干!!
这个学习案例,主要是参考b站大佬的备忘录设计和华为开辟者官网的例子记账本,大家也可以在了解根本关系型数据库怎么设置后详细学习
我们主要/scr/main的目录布局如下:
../scr/main目录下文件树结构展示
.
|-- constants
|   `-- CommonConstants.ets
|-- database
|   |-- MemoTable.ets
|   `-- Rdb.ets
|-- ets
|   |-- component
|   |   `-- MemoItem.ets
|   |-- entryability
|   |   `-- EntryAbility.ts
|   `-- pages
|       `-- Index.ets
|-- model
|   |-- MemoModel.ets
|   `-- TableInterface.ets
|-- module.json5
|-- resources
|   |-- base
|   |   |-- element
|   |   |   |-- color.json
|   |   |   `-- string.json
|   |   |-- media
|   |   |   `-- icon.png
|   |   `-- profile
|   |       `-- main_pages.json
|   |-- en_US
|   |   `-- element
|   |       `-- string.json
|   |-- rawfile
|   `-- zh_CN
|       `-- element
|         `-- string.json
`-- utils
    `-- Logger.ets

数据库的设置

我们先设置数据库
在./main/constants目录下,创建CommonConstants.ets文件,在这个文件里,我们存放Rdb数据库的根本设置,详细跟官网样例也差不多
import relationalStore from '@ohos.data.relationalStore'
import { MemoTable } from '../model/TableInterface'

export default class CommonConstants {

// Rdb 数据库配置
static readonly STORE_CONFIG:relationalStore.StoreConfig = {
    name:'database.db',
    securityLevel:relationalStore.SecurityLevel.S1
}

static readonly MEMO_TABLE:MemoTable = {
    tableName:'memoTable',
    sqlCreate:'CREATE TABLE IF NOT EXISTS memoTable(id INTEGER PRIMARY KEY AUTOINCREMENT, updateTime INTEGER, content TEXT)',
    columns:['id','updateTime','content']
}

// 一些日志控制参数
static readonly RDB_TAG = '';
static readonly TABLE_TAG = '';
static readonly INDEX_TAG = '';

}
我在学习的时间注意到,大佬在/main/model目录下,设置了TableInterface.ets文件,存放了一个MeMoTable接口
这种接口的设置,不用设置关键词function,我认识到大概一个是为了给CommonConstants类中的MEMO_TABLE内部元素设置类型,一个是降低代码耦合度便于后面维护
在/main/model目录下,新建TableInterface.ets文件,写一个MeMoTable接口
```typescript
export interface MemoTable {
tableName: string
sqlCreate: string
columns: string[]
}
原来的界说如下
interface 接口名{
    接口代码:一般定义规则、方法等
    方法名(形参:形参类型):方法返回值
}
进一步,大佬对数据库的操作进行了一层抽象,这个抽象的意思就是把很复杂的操作用几个函数给你概括起来了
   就像我们假如形容一辆车,我们原来按照比较机器的方法,要界说外壳轮廓、动力参数什么的,现在直接告诉你小轿车、发动机V8什么的,你就大概了解了,我想后者就是抽象,把复杂的东西简朴化
在/main/database目录下,新建Rdb.ets文件,这个文件就是负责抽象复杂的数据库操作方法,不用来实现详细业务,只规定获取rdbStore对象,并用哪张表增删改查之类的流程
我们后续要使用数据库的数据操作时,数据操作也被简化为getRdbStore, insertData, deleteData, updateData, query方法
import relationalStore from '@ohos.data.relationalStore';
import CommonConstants from '../constants/CommonConstants';
import Logger from '../utils/Logger';

// 抽象的Rdb类,没有业务属性,可以基于这个类创建带有业务属性的一张或多张表

export default class Rdb {

// 管理关系数据库(RDB)方法属性 类型是RdbStore 或 null
private rdbStore: relationalStore.RdbStore | null = null;

// 数据库表名称
private tableName: string;

// 创建SQLite表的语句字符串
private sqlCreateTable: string;

// 列名字段的数组
private columns: Array<string>;

// 实例化 Rdb 对象时,初始化表名、创建表的语句、列名字段的数组
constructor(tableName: string, sqlCreateTable: string, columns: Array<string>) {
    this.tableName = tableName;
    this.sqlCreateTable = sqlCreateTable;
    this.columns = columns;
}

// 获取操作数据库RdbStore对象的方法,接收一个回调函数
getRdbStore(callback: Function = () => {
}) {
    // 如果 回调函数为空、或undefined 打印错误日志,退出方法
    if (!callback || typeof callback === 'undefined' || callback === undefined) {
      Logger.info(CommonConstants.RDB_TAG, 'getRdbStore() has no callback!');
      return;
    }

    // 如果属性rdbStore 不为空,说明操作对象已经初始化,打印日志,执行回调函数,退出方法
    if (this.rdbStore !== null) {
      Logger.info(CommonConstants.RDB_TAG, 'The rdbStore exists.');
      callback();
      return
    }

    // 执行到此处,说明回调函数不为空,且rdbStore尚未初始化

    // 获取上下文
    let context: Context = getContext(this) as Context;

    /*
      获取RdbStore接口的方法,接收三个参数
      context:应用上下文
      config   :数据库配置
      callback :回调函数,异步返回rdb对象
    */
    relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG, (err, rdb) => {
      // 如果发生错误,打印日志,退出方法
      if (err) {
      Logger.error(CommonConstants.RDB_TAG, `gerRdbStore() failed, err: ${err}`);
      return;
      }
      // 如果没有错误,为rdbStore属性赋值为rdb
      this.rdbStore = rdb;
      // 执行Sql语句,使用创建表的字符串
      this.rdbStore.executeSql(this.sqlCreateTable);
      // 打印日志
      Logger.info(CommonConstants.RDB_TAG, 'getRdbStore() finished.');
      // 执行方法入参的回调函数
      callback();
    });
}

// 插入数据的方法,入参为表格的存储键值对,和回调函数
insertData(data: relationalStore.ValuesBucket, callback: Function = () => {
}) {
    // 如果回调函数为空、或undefined 打印错误日志,退出方法
    if (!callback || typeof callback === 'undefined' || callback === undefined) {
      Logger.info(CommonConstants.RDB_TAG, 'insertData() has no callback!');
      return;
    }
    // 创建结果标识局部变量,默认为false
    let resFlag: boolean = false;
    // 创建存储键值对局部变量,默认为入参data
    const valueBucket: relationalStore.ValuesBucket = data;
    // 如果rdbStore存在则执行
    if (this.rdbStore) {
      // 执行rdbStore的插入数据方法,入参为表名、存储键值对、异步回调函数
      this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => {
      if (err) {
          // 如果发生错误,打印日志,执行入参的回调函数,并传入结果标识 false
          Logger.error(CommonConstants.RDB_TAG, `insertData() failed, err: ${err}`);
          callback(resFlag);
          return;
      }
      // 如果操作成功,打印日志,执行回调函数,并传入返回ret(行ID)
      Logger.info(CommonConstants.RDB_TAG, `insertData() finished: ${ret}`);
      callback(ret);
      });
    }
}

// 删除数据的方法,接收谓词和回调函数两个参数
deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => {
}) {
    // 如果回调函数为空、或undefined 打印错误日志,退出方法
    if (!callback || typeof callback === 'undefined' || callback === undefined) {
      Logger.info(CommonConstants.RDB_TAG, 'deleteData() has no callback!');
      return;
    }
    // 创建结果标识局部变量,默认为false
    let resFlag: boolean = false;
    // 如果rdbStore存在则执行
    if (this.rdbStore) {
      // rdbStore的删除方法,入参为谓词、异步回调函数
      this.rdbStore.delete(predicates, (err, ret) => {
      // 如果发生错误,打印日志,执行入参的回调函数,并传入结果标识 false
      if (err) {
          Logger.error(CommonConstants.RDB_TAG, `deleteData() failed, err: ${err}`);
          callback(resFlag);
          return;
      }
      // 如果删除成功,打印日志,执行回调函数,并传入返回ret(行ID)
      Logger.info(CommonConstants.RDB_TAG, `deleteData() finished: ${ret}`);
      callback(!resFlag);
      });
    }
}

// 更新数据的方法,接收三个参数:谓词、存储键值对、回调函数
updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => {
}) {
    // 如果回调函数为空、或undefined 打印错误日志,退出方法
    if (!callback || typeof callback === 'undefined' || callback === undefined) {
      Logger.info(CommonConstants.RDB_TAG, 'updateDate() has no callback!');
      return;
    }
    // 创建结果标识局部变量,默认为false
    let resFlag: boolean = false;
    // 创建存储键值对局部变量,默认为入参data
    const valueBucket: relationalStore.ValuesBucket = data;
    // 如果rdbStore存在则执行
    if (this.rdbStore) {
      // rdbStore的更新方法,接收三个参数,存储键值对、谓词、回调函数
      this.rdbStore.update(valueBucket, predicates, (err, ret) => {
      if (err) {
          // 如果发生错误,打印日志,执行入参的回调函数,并传入结果标识 false
          Logger.error(CommonConstants.RDB_TAG, `updateData() failed, err: ${err}`);
          callback(resFlag);
          return;
      }
      // 如果更新成功,打印日志,执行回调函数,并传入返回成功的标识 true
      Logger.info(CommonConstants.RDB_TAG, `updateData() finished: ${ret}`);
      callback(!resFlag);
      });
    }
}

// 查询数据的方法,接收两个参数,谓词、回调函数
query(predicates: relationalStore.RdbPredicates, callback: Function = () => {
}) {
    // 如果回调函数为空、或undefined 打印错误日志,退出方法
    if (!callback || typeof callback === 'undefined' || callback === undefined) {
      Logger.info(CommonConstants.RDB_TAG, 'query() has no callback!');
      return;
    }
    // 如果rdbStore存在则执行
    if (this.rdbStore) {
      // rdbStore的查询方法,接收三个参数,谓词,数据库列名的数组,异步回调函数
      this.rdbStore.query(predicates, this.columns, (err, resultSet) => {
      // 如果发生错误,打印日志,退出方法
      if (err) {
          Logger.error(CommonConstants.RDB_TAG, `query() failed, err:${err}`);
          return;
      }
      // 如果没有错误,打印日志
      Logger.info(CommonConstants.RDB_TAG, 'query() finished.');
      // 执行入参的回调函数,传入查询结果
      callback(resultSet);
      // 关闭结果集
      resultSet.close();
      });
    }
}

}
数据实现

接下来我们来写详细的数据
我们在/main/model目录下创建MeMoModel.ets,设置数据类,设置类MeMoModel,这个类用来管理添加的备忘录的根本信息
class MemoModel {
id: number
updateTime: number
content: string

constructor(id: number, updateTime: number, content: string) {
    this.id = id
    this.updateTime = updateTime
    this.content = content
}
}

export default MemoModel
我们在/main/database目录下创建MemoTable.ets,这个是用来进行备忘录详细业务逻辑操作的
我们一开始先实例化Rdb类,然后依次获取getRdbStore,insertData,deleteData,updateData,query方法,我们在这里的方法里,可以详细设置我们业务数据怎么处理的,比如在query里,我们是根据须要组装变量tmp,并且加到result中
import relationalStore from '@ohos.data.relationalStore';
import MemoModel from '../model/MemoModel'
import CommonConstants from '../constants/CommonConstants';
import Rdb from './Rdb';

// 笔记的数据库类,基于Rdb类,有业务属性
export default class MemoTable {
// 通过Rdb类实例化memoTable对象,使用常量文件“CommonConstants”中配置的参数
private memoTable = new Rdb(CommonConstants.MEMO_TABLE.tableName, CommonConstants.MEMO_TABLE.sqlCreate,
    CommonConstants.MEMO_TABLE.columns);

// 构造函数,执行getRdbStore方法
constructor(callback: Function = () => {
}) {
    this.memoTable.getRdbStore(callback);
}
// 通过memoTable对象,执行原Rdb类中的getRdbStore方法,为memoTable对象获取rdbStore操作对象
getRdbStore(callback: Function = () => {
}) {
    // 透传回调函数
    this.memoTable.getRdbStore(callback);
}

// 插入数据的方法,接收单条memo笔记对象,和回调函数
insertData(memo: MemoModel, callback: Function) {
    // 通过工具函数,将单条memo笔记,转化为存储健值对
    const valueBucket: relationalStore.ValuesBucket = generateBucket(memo);
    // 执行memoTable的插入数据方法,透传回调函数
    this.memoTable.insertData(valueBucket, callback);
}

// 删除数据的方法,接收单条memo笔记对象,和回调函数
deleteData(memo: MemoModel, callback: Function) {
    // 初始化操作数据库的谓词对象
    let predicates = new relationalStore.RdbPredicates(CommonConstants.MEMO_TABLE.tableName);
    // 配置谓词以匹配数据表的id列中值的字段,为笔记对象的id
    predicates.equalTo('id', memo.id);
    // 使用谓词执行memoTable的删除方法,透传回调函数
    this.memoTable.deleteData(predicates, callback);
}

// 更新数据的方法,接收单条memo笔记对象,和回调函数
updateData(memo: MemoModel, callback: Function) {
    // 通过工具函数,将单条memo笔记,转化为存储健值对
    const valueBucket: relationalStore.ValuesBucket = generateBucket(memo);
    // 初始化操作数据库的谓词对象
    let predicates = new relationalStore.RdbPredicates(CommonConstants.MEMO_TABLE.tableName);
    // 配置谓词以匹配数据表的id列中值的字段,为笔记对象的id
    predicates.equalTo('id', memo.id);
    // 使用谓词执行memoTable的更新方法,透传回调函数
    this.memoTable.updateData(predicates, valueBucket, callback);
}

// 查询全部笔记的方法
query(callback: Function) {
    // 初始化操作数据库的谓词对象
    let predicates = new relationalStore.RdbPredicates(CommonConstants.MEMO_TABLE.tableName);
    // 使用谓词执行memoTable的查询方法,此时谓词匹配未指定(equalTo),所以将查询全部
    this.memoTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
      // 创建局部变量,存储结果的行数
      let count: number = resultSet.rowCount;
      // 如果查询的结果为0,执行回调函数,传入空数组
      if (count === 0 || typeof count === 'string') {
      console.log(`${CommonConstants.TABLE_TAG}` + 'Query no results!');
      callback([]);
      } else {
      // 如果有结果,将结果集指向第一行
      resultSet.goToFirstRow();
      // 创建局部变量,存储最后将返回的结果数组
      const result: MemoModel[] = [];
      // 使用循环为结果添加内容
      for (let i = 0; i < count; i++) {
          let tmp: MemoModel = {
            id: 0, updateTime: 0, content: ''
          };
          tmp.id = resultSet.getDouble(resultSet.getColumnIndex('id'));
          tmp.updateTime = resultSet.getDouble(resultSet.getColumnIndex('updateTime'));
          tmp.content = resultSet.getString(resultSet.getColumnIndex('content'));
          result = tmp;
          // 转至下一行
          resultSet.goToNextRow();
      }
      // 执行回调函数,把所有的查询结果传入
      callback(result);
      }
    });
}
}

// 工具函数,将memo笔记的数据结构,转化为存储键值对
function generateBucket(memo: MemoModel): relationalStore.ValuesBucket {
let obj: relationalStore.ValuesBucket = {};
obj.updateTime = memo.updateTime
obj.content = memo.content
return obj;
}
页面设置

我们先在Index.ets目录下,设置一个简朴的页面,可以或许实现备忘录根本样式,并且能添加大略卡片样式的列表
@Entry
@Component
struct Index {
// 缓存的原始数组
originMemoList: MemoModel[] = []
// 页面中展示的memo列表
@State memoList: MemoModel[] = []
// 新建暂存内容
@State addContent: string = ''

@State number: number = 1

// 当前编辑的memo索引
editingMemoIndex: number = -1

build() {
   Stack() {
   // 主体页面
   Column() {
       Row() {
         Text("MeMo")
         .fontSize(20)
         .fontColor(Color.White)
         .margin({ left:20})
         Blank()
         Button() {
         Text("我是按钮")
             .fontSize(20)
             .fontColor(Color.White)
         }
         .height(40)
         .width(150)
         .onClick(() => {
         this.number = this.number + 1
         })
       }
       .width('100%')
       .height(60)
       .linearGradient({
         direction:GradientDirection.Bottom,
         colors:[, ]
       })
       .shadow({
         radius:10
       })

       Divider()
         .color('#604637')

       // 笔记列表
       Scroll() {
         Column() {
            Text(String(this.number))
            .fontSize(40)
         List({space: 10}) {
             ForEach(this.memoList, (item: MemoModel, index) => {
                ListItem() {
                  Row() {
                  Text(item.content)
                  Text(String(item.updateTime))
                  }
                }.card()
             })
         }
         }
       }

   }
   .width('100%')
   .height('100%')
   }
}
}
手机模仿器界面如下
https://img-blog.csdnimg.cn/direct/04ff182f2c36445493bde65582ff8cd3.png#pic_center
注意看,我这里是不能用它自带的Previewer进行展示的,我的Previewer会呈空缺
https://img-blog.csdnimg.cn/direct/ca22503538154634a6d4879bd89a106a.png#pic_center
我感觉很少人说过这个,网上超少,而且这个情况是我一旦使用了数据库之后,他立马就会变成空缺,只能用手机模仿器显示,我想大概Previewer不能涉及有数据相关的操作,而真机模仿就可以。
功能展示

功能很简朴,如下,并且应用关闭了之后,数据也不会丢失,会继续保存下来。
https://img-blog.csdnimg.cn/direct/2d3d0558e3d34d81b028f21a4122c15a.png#pic_center
https://img-blog.csdnimg.cn/direct/50eb72de08024f5f8c59d823a2ad83b7.png#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 基于鸿蒙OS4的关系数据库使用学习——以浅易版备忘录为例