鸿蒙实战开发-利用关系型数据库实现对账单的增、删、改、查 ...

打印 上一主题 下一主题

主题 928|帖子 928|积分 2784

先容

本Codelab以记账为例,利用关系型数据库的相关接口实现了对账单的增、删、改、查操作。实现结果如图所示:

相关概念



  • 关系型数据库:基于关系模子来管理数据的数据库,提供了增、删、改、查等接口,也可运行输入的SQL语句满足复杂场景必要。
环境搭建

软件要求



  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。
硬件要求



  • 开发板类型:润和RK3568开发板。
  • OpenHarmony体系:3.2 Release。
环境搭建

完资本篇Codelab我们起首要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步调进行:

  • 获取OpenHarmony体系版本:尺度体系办理方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。


  • 完成DevEco Device Tool的安装
  • 完成RK3568开发板的烧录
3.搭建开发环境。


  • 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  • 开发环境配置完成后,请参考利用工程领导创建工程(模板选择“Empty Ability”),选择JS大概eTS语言开发。
  • 工程创建完成后,选择利用真机进行调测。
代码结构解读

本篇Codelab只对核心代码进行讲解,
  1. ├──entry/src/main/ets               // 代码区
  2. │  ├──common
  3. │  │  ├──constants
  4. │  │  │  └──CommonConstants.ets     // 公共常量
  5. │  │  ├──database
  6. │  │  │  ├──tables
  7. │  │  │  │  └──AccountTable.ets     // 账目数据表
  8. │  │  │  └──Rdb.ets                 // RDB数据库
  9. │  │  └──utils                      // 日志类
  10. │  │     ├──ConsoleLogger.ets
  11. │  │     ├──HiLogger.ets
  12. │  │     ├──ILogger.ets
  13. │  │     └──Logger.ets
  14. │  ├──entryability
  15. │  │  └──EntryAbility.ts            // 程序入口类
  16. │  ├──pages
  17. │  │  └──MainPage.ets               // 应用首页
  18. │  ├──view
  19. │  │  └──DialogComponent.ets        // 自定义弹窗
  20. │  └──viewmodel
  21. │     ├──AccountData.ets            // 账目类接口
  22. │     ├──AccountItem.ets            // 账目资源类接口
  23. │     ├──AccountList.ets            // 账目类型model
  24. │     └──ConstantsInterface.ets     // 常量接口
  25. └──entry/src/main/resources         // 资源文件夹
复制代码
创建数据库

要利用关系型数据库存储用户数据,起首要进行数据库的创建,并提供根本的增、删、改、查接口。
导入关系型数据库模块:
  1. import relationalStore from '@ohos.data.relationalStore';
复制代码
关系型数据库提供以下两个根本功能:

起首要获取一个RdbStore实例来操作关系型数据库,代码如下
  1. // Rdb.ets
  2. getRdbStore(callback: Function = () => {
  3. }) {
  4.   // 如果已经获取到RdbStore则不做操作
  5.   if (!callback || typeof callback == 'undefined' || callback == undefined) {
  6.     Logger.verbose(`${CommonConstants.RDB_TAG}`, 'getRdbStore() has no callback!');
  7.     return;
  8.   }
  9.   
  10.   // 应用上下文,本Codelab使用API9 Stage模型的Context
  11.   let context: Context = getContext(this) as Context;
  12.   relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG, (err, rdb) => {
  13.     if (err) {
  14.       Logger.error(`${RDB_TAG}`, 'gerRdbStore() failed, err: ' + err);
  15.       return;
  16.     }
  17.     this.rdbStore = rdb;
  18.     // 获取到RdbStore后,需使用executeSql接口初始化数据库表结构和相关数据
  19.     this.rdbStore.executeSql(this.sqlCreateTable);         
  20.     Logger.verbose(`${RDB_TAG}`, 'getRdbStore() finished.');
  21.     callback();
  22.   });
  23. }
复制代码
关系型数据库接口提供的增、删、改、查操作均有callback和Promise两种异步回调方式,本Codelab利用了callback异步回调,其中插入数据利用了insert()接口,实当代码如下:
  1. // Rdb.ets
  2. insertData(data: relationalStore.ValuesBucket, callback: Function = () => {
  3. }) {
  4.   if (!callback || typeof callback == 'undefined' || callback == undefined) {
  5.     Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() has no callback!');
  6.     return;
  7.   }
  8.   let resFlag: boolean = false;
  9.   const valueBucket: relationalStore.ValuesBucket = data;
  10.   if (this.rdbStore) {
  11.     this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => {
  12.       if (err) {
  13.         Logger.error(`${CommonConstants.RDB_TAG}`, 'insertData() failed, err: ' + err);
  14.         callback(resFlag);
  15.         return;
  16.       }
  17.       Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() finished: ' + ret);
  18.       callback(ret);
  19.     });
  20.   }
  21. }
复制代码
删除数据利用了delete()接口,实当代码如下:
  1. // Rdb.ets
  2. deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  3. }) {
  4.   if (!callback || typeof callback == 'undefined' || callback == undefined) {
  5.     Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() has no callback!');
  6.     return;
  7.   }
  8.   let resFlag: boolean = false;
  9.   if (this.rdbStore) {
  10.     this.rdbStore.delete(predicates, (err, ret) => {
  11.       if (err) {
  12.         Logger.error(`${CommonConstants.RDB_TAG}`, 'deleteData() failed, err: ' + err);
  13.         callback(resFlag);
  14.         return;
  15.       }
  16.       Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() finished: ' + ret);
  17.       callback(!resFlag);
  18.     });
  19.   }
  20. }
复制代码
更新数据利用了update()接口,实当代码如下:
  1. // Rdb.ets
  2. updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => {
  3. }) {
  4.   if (!callback || typeof callback == 'undefined' || callback == undefined) {
  5.     Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateDate() has no callback!');
  6.     return;
  7.   }
  8.   let resFlag: boolean = false;
  9.   const valueBucket: relationalStore.ValuesBucket = data;
  10.   if (this.rdbStore) {
  11.     this.rdbStore.update(valueBucket, predicates, (err, ret) => {
  12.       if (err) {
  13.         Logger.error(`${CommonConstants.RDB_TAG}`, 'updateData() failed, err: ' + err);
  14.         callback(resFlag);
  15.         return;
  16.       }
  17.       Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateData() finished: ' + ret);
  18.       callback(!resFlag);
  19.     });
  20.   }
  21. }
复制代码
查找数据利用了query()接口,实当代码如下:
  1. // Rdb.ets
  2. query(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  3. }) {
  4.   if (!callback || typeof callback == 'undefined' || callback == undefined) {
  5.     Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() has no callback!');
  6.     return;
  7.   }
  8.   if (this.rdbStore) {
  9.     this.rdbStore.query(predicates, this.columns, (err, resultSet) => {
  10.       if (err) {
  11.         Logger.error(`${CommonConstants.RDB_TAG}`, 'query() failed, err: ' + err);
  12.         return;
  13.       }
  14.       Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() finished.');
  15.       callback(resultSet);
  16.       resultSet.close();
  17.     });
  18.   }
  19. }
复制代码
本Codelab必要记载账目的类型(收入/支出)、具体类别和金额,因此必要创建一张存储账目信息的表,表头如下:

创建该表的SQL语句为:
  1. CREATE TABLE IF NOT EXISTS accountTable(
  2.     id INTEGER PRIMARY KEY AUTOINCREMENT,
  3.     accountType INTEGER,
  4.     typeText TEXT,
  5.     amount INTEGER
  6. )
复制代码
该表必要封装增、删、改、查接口,代码如下:
  1. // AccountTable.ets
  2. // 插入数据
  3. insertData(account: AccountData, callback: Function) {
  4.   // 根据输入数据创建待插入的数据行
  5.   const valueBucket: relationalStore.ValuesBucket = generateBucket(account);
  6.   this.accountTable.insertData(valueBucket, callback);
  7. }
  8. // 删除数据
  9. deleteData(account: AccountData, callback: Function) {
  10.   let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName);
  11.   
  12.   // 根据id匹配待删除的数据行
  13.   predicates.equalTo('id', account.id);
  14.   this.accountTable.deleteData(predicates, callback);
  15. }
  16. // 修改数据
  17. updateData(account: AccountData, callback: Function) {
  18.   const valueBucket: relationalStore.ValuesBucket = generateBucket(account);
  19.   let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName);
  20.   // 根据id匹配待删除的数据行
  21.   predicates.equalTo('id', account.id);
  22.   this.accountTable.updateData(predicates, valueBucket, callback);
  23. }
  24. // 查找数据
  25. query(amount: number, callback: Function, isAll: boolean = true) {
  26.   let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName);
  27.   if (!isAll) {
  28.     predicates.equalTo('amount', amount);
  29.   }
  30.   this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
  31.     let count: number = resultSet.rowCount;
  32.     if (count === 0 || typeof count === 'string') {
  33.       console.log(`${CommonConstants.TABLE_TAG}` + 'Query no results!');
  34.       callback([]);
  35.     } else {
  36.       resultSet.goToFirstRow();
  37.       const result: AccountData[] = [];
  38.       for (let i = 0; i < count; i++) {
  39.         let tmp: AccountData = { id: 0, accountType: 0, typeText: '', amount: 0 };
  40.         tmp.id = resultSet.getDouble(resultSet.getColumnIndex('id'));
  41.         tmp.accountType = resultSet.getDouble(resultSet.getColumnIndex('accountType'));
  42.         tmp.typeText = resultSet.getString(resultSet.getColumnIndex('typeText'));
  43.         tmp.amount = resultSet.getDouble(resultSet.getColumnIndex('amount'));
  44.         result[i] = tmp;
  45.         resultSet.goToNextRow();
  46.       }
  47.       callback(result);
  48.     }
  49.   });
  50. }
复制代码
功能实现

起首创建应用主页面,主要包括利用Search组件创建的搜索栏和利用List组件创建的账目清单,如下图所示:

在打开应用时,必要查询数据库中存储的账目并显示在主页面,因此生命周期函数aboutToAppear()应写为:
  1. // Mainpage.ets
  2. aboutToAppear() {
  3.   this.AccountTable.getRdbStore(() => {  // 获取数据库
  4.     this.AccountTable.query(0, (result: AccountData[]) => {  // 查询数据库中的全部账目
  5.       this.accounts = result;
  6.     }, true);
  7.   });
  8. }
复制代码
点击右上角的“编辑”图标,主页面变为如下结果:

可以选中必要删除的账目,点击下方“删除”图标后删除对应账目,对应代码如下:
  1. // Mainpage.ets
  2. deleteListItem() {
  3.   for (let i = 0; i < this.deleteList.length; i++) {  // 删除每一项选中的账目并更新页面上的账目清单
  4.     let index = this.accounts.indexOf(this.deleteList[i]);
  5.     this.accounts.splice(index, 1);
  6.     this.AccountTable.deleteData(this.deleteList[i], () => {});
  7.   }
  8.   this.deleteList = [];
  9.   this.isEdit = false;
  10. }
复制代码
搜索栏在键入文本并回车时,实现搜索功能:
  1. // Mainpage.ets
  2. .onSubmit((searchValue: string) => {
  3.   if (searchValue === '') {  // 如果搜索栏为空,查找全部账目
  4.     this.AccountTable.query(0, (result: AccountData[]) => {
  5.       this.accounts = result;
  6.     }, true);
  7.   } else {
  8.     this.AccountTable.query(Number(searchValue), (result: AccountData[]) => {  // 查找金额为val的账目
  9.       this.accounts = result;
  10.     }, false);
  11.   }
  12. })
复制代码
右下角的“添加”按钮可以打开一个自定义弹窗,并在弹窗里新建账目信息:
  1. // Mainpage.ets
  2. .onClick(() => {
  3.   this.isInsert = true;  // 插入模式
  4.   this.newAccount = { id: 0, accountType: 0, typeText: '', amount: 0 };
  5.   this.dialogController.open();
  6. })
复制代码
点击账目清单中的某个账目,也可以打开自定义弹窗,并修改账目信息:
  1. // Mainpage.ets
  2. selectListItem(item: AccountData) {
  3.   this.isInsert = false;  // 编辑模式
  4.   this.index = this.accounts.indexOf(item);
  5.   this.newAccount = {
  6.     id: item.id,
  7.     accountType: item.accountType,
  8.     typeText: item.typeText,
  9.     amount: item.amount
  10.   };
  11. }
复制代码
自定义弹窗由利用Tabs组件创建的账目类别、利用TextInput组件创建的输入栏和确定按钮构成,如下图所示:

点击“确定”按钮会调用accept()函数,根据isInsert的值来进行账目的添加或修改,代码如下:
  1. // Mainpage.ets
  2. accept(isInsert: boolean, newAccount: AccountData): void {
  3.   if (isInsert) {  // 插入模式,往数据库插入一个新账目
  4.     Logger.verbose(`${CommonConstants.INDEX_TAG}`, 'The account inserted is: ' + JSON.stringify(newAccount));
  5.     this.AccountTable.insertData(newAccount, (id: number) => {
  6.       newAccount.id = id;
  7.       this.accounts.push(newAccount);
  8.     });
  9.   } else {  // 编辑模式,更新当前选中的账目并写入数据库,刷新页面的账目清单
  10.     this.AccountTable.updateData(newAccount, () => {});
  11.     let list = this.accounts;
  12.     this.accounts = [];
  13.     list[this.index] = newAccount;
  14.     this.accounts = list;
  15.     this.index = -1;
  16.   }
  17. }
复制代码

通过本Codelab的学习,您已经学会了关系型数据库的根本用法。
总结

您已经完成了本次Codelab的学习,并学会了利用关系型数据库的相关接口实现对数据的增、删、改、查操作。
为了帮助各人更深入有效的学习到鸿蒙开发知识点,小编特意给各人准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频
HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程



鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击《鸿蒙生态应用开发白皮书V2.0PDF》

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  • 应用开发导读(ArkTS)
  • ……


二、HarmonyOS 概念

  • 体系定义
  • 技术架构
  • 技术特性
  • 体系安全
  • ........


三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》


  • 根本概念
  • 构建第一个ArkTS应用
  • ……


四、开发基础知识


  • 应用基础知识
  • 配置文件
  • 应用数据管理
  • 应用安全管理
  • 应用隐私保护
  • 三方应用调用管控机制
  • 资源分类与访问
  • 学习ArkTS语言
  • ……

五、基于ArkTS 开发


  • Ability开发
  • UI开发
  • 公共事件与通知
  • 窗口管理
  • 媒体
  • 安全
  • 网络与链接
  • 电话服务
  • 数据管理
  • 后台使命(Background Task)管理
  • 装备管理
  • 装备利用信息统计
  • DFX
  • 国际化开发
  • 折叠屏系列
  • ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦见你的名字

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表