介紹
本Codelab以記賬為例,使用關(guān)系型數(shù)據(jù)庫(kù)的相關(guān)接口實(shí)現(xiàn)了對(duì)賬單的增、刪、改、查操作。實(shí)現(xiàn)效果如圖所示:
相關(guān)概念
- [關(guān)系型數(shù)據(jù)庫(kù)]:基于關(guān)系模型來管理數(shù)據(jù)的數(shù)據(jù)庫(kù),提供了增、刪、改、查等接口,也可運(yùn)行輸入的SQL語句滿足復(fù)雜場(chǎng)景需要。
環(huán)境搭建
軟件要求
- [DevEco Studio]版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
硬件要求
- 開發(fā)板類型:[潤(rùn)和RK3568開發(fā)板]。
- OpenHarmony系統(tǒng):3.2 Release。
環(huán)境搭建
完成本篇Codelab我們首先要完成開發(fā)環(huán)境的搭建,本示例以RK3568開發(fā)板為例,參照以下步驟進(jìn)行:
- [獲取OpenHarmony系統(tǒng)版本]:標(biāo)準(zhǔn)系統(tǒng)解決方案(二進(jìn)制)。以3.2 Release版本為例:
- 搭建燒錄環(huán)境。
- 搭建開發(fā)環(huán)境。
- 開始前請(qǐng)參考[工具準(zhǔn)備],完成DevEco Studio的安裝和開發(fā)環(huán)境配置。
- 開發(fā)環(huán)境配置完成后,請(qǐng)參考[使用工程向?qū)創(chuàng)建工程(模板選擇“Empty Ability”),選擇JS或者eTS語言開發(fā)。
- 工程創(chuàng)建完成后,選擇使用[真機(jī)進(jìn)行調(diào)測(cè)]。
代碼結(jié)構(gòu)解讀
本篇只對(duì)核心代碼進(jìn)行講解,完整代碼可以直接從gitee獲取。
├──entry/src/main/ets // 代碼區(qū)
│ ├──common
│ │ ├──constants
│ │ │ └──CommonConstants.ets // 公共常量
│ │ ├──database
│ │ │ ├──tables
│ │ │ │ └──AccountTable.ets // 賬目數(shù)據(jù)表
│ │ │ └──Rdb.ets // RDB數(shù)據(jù)庫(kù)
│ │ └──utils // 日志類
│ │ ├──ConsoleLogger.ets
│ │ ├──HiLogger.ets
│ │ ├──ILogger.ets
│ │ └──Logger.ets
│ ├──entryability
│ │ └──EntryAbility.ts // 程序入口類
│ ├──pages
│ │ └──MainPage.ets // 應(yīng)用首頁(yè)
│ ├──view
│ │ └──DialogComponent.ets // 自定義彈窗
│ └──viewmodel
│ ├──AccountData.ets // 賬目類接口
│ ├──AccountItem.ets // 賬目資源類接口
│ ├──AccountList.ets // 賬目類型model
│ └──ConstantsInterface.ets // 常量接口
└──entry/src/main/resources // 資源文件夾
創(chuàng)建數(shù)據(jù)庫(kù)
要使用關(guān)系型數(shù)據(jù)庫(kù)存儲(chǔ)用戶數(shù)據(jù),首先要進(jìn)行數(shù)據(jù)庫(kù)的創(chuàng)建,并提供基本的增、刪、改、查接口。
導(dǎo)入關(guān)系型數(shù)據(jù)庫(kù)模塊:
import relationalStore from '@ohos.data.relationalStore';
關(guān)系型數(shù)據(jù)庫(kù)提供以下兩個(gè)基本功能:
首先要獲取一個(gè)RdbStore實(shí)例來操作關(guān)系型數(shù)據(jù)庫(kù),代碼如下:
// Rdb.ets
getRdbStore(callback: Function = () = > {
}) {
// 如果已經(jīng)獲取到RdbStore則不做操作
if (!callback || typeof callback == 'undefined' || callback == undefined) {
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'getRdbStore() has no callback!');
return;
}
// 應(yīng)用上下文,本Codelab使用API9 Stage模型的Context
let context: Context = getContext(this) as Context;
relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG, (err, rdb) = > {
if (err) {
Logger.error(`${RDB_TAG}`, 'gerRdbStore() failed, err: ' + err);
return;
}
this.rdbStore = rdb;
// 獲取到RdbStore后,需使用executeSql接口初始化數(shù)據(jù)庫(kù)表結(jié)構(gòu)和相關(guān)數(shù)據(jù)
this.rdbStore.executeSql(this.sqlCreateTable);
Logger.verbose(`${RDB_TAG}`, 'getRdbStore() finished.');
callback();
});
}
關(guān)系型數(shù)據(jù)庫(kù)接口提供的增、刪、改、查操作均有callback和Promise兩種異步回調(diào)方式,本Codelab使用了callback異步回調(diào),其中插入數(shù)據(jù)使用了insert()接口,實(shí)現(xiàn)代碼如下:
// Rdb.ets
insertData(data: relationalStore.ValuesBucket, callback: Function = () = > {
}) {
if (!callback || typeof callback == 'undefined' || callback == undefined) {
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() has no callback!');
return;
}
let resFlag: boolean = false;
const valueBucket: relationalStore.ValuesBucket = data;
if (this.rdbStore) {
this.rdbStore.insert(this.tableName, valueBucket, (err, ret) = > {
if (err) {
Logger.error(`${CommonConstants.RDB_TAG}`, 'insertData() failed, err: ' + err);
callback(resFlag);
return;
}
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'insertData() finished: ' + ret);
callback(ret);
});
}
}
刪除數(shù)據(jù)使用了delete()接口,實(shí)現(xiàn)代碼如下:
// Rdb.ets
deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () = > {
}) {
if (!callback || typeof callback == 'undefined' || callback == undefined) {
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() has no callback!');
return;
}
let resFlag: boolean = false;
if (this.rdbStore) {
this.rdbStore.delete(predicates, (err, ret) = > {
if (err) {
Logger.error(`${CommonConstants.RDB_TAG}`, 'deleteData() failed, err: ' + err);
callback(resFlag);
return;
}
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'deleteData() finished: ' + ret);
callback(!resFlag);
});
}
}
更新數(shù)據(jù)使用了update()接口,實(shí)現(xiàn)代碼如下:
// Rdb.ets
updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () = > {
}) {
if (!callback || typeof callback == 'undefined' || callback == undefined) {
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateDate() has no callback!');
return;
}
let resFlag: boolean = false;
const valueBucket: relationalStore.ValuesBucket = data;
if (this.rdbStore) {
this.rdbStore.update(valueBucket, predicates, (err, ret) = > {
if (err) {
Logger.error(`${CommonConstants.RDB_TAG}`, 'updateData() failed, err: ' + err);
callback(resFlag);
return;
}
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'updateData() finished: ' + ret);
callback(!resFlag);
});
}
}
查找數(shù)據(jù)使用了query()接口,實(shí)現(xiàn)代碼如下:
// Rdb.ets
query(predicates: relationalStore.RdbPredicates, callback: Function = () = > {
}) {
if (!callback || typeof callback == 'undefined' || callback == undefined) {
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() has no callback!');
return;
}
if (this.rdbStore) {
this.rdbStore.query(predicates, this.columns, (err, resultSet) = > {
if (err) {
Logger.error(`${CommonConstants.RDB_TAG}`, 'query() failed, err: ' + err);
return;
}
Logger.verbose(`${CommonConstants.RDB_TAG}`, 'query() finished.');
callback(resultSet);
resultSet.close();
});
}
}
本Codelab需要記錄賬目的類型(收入/支出)、具體類別和金額,因此需要?jiǎng)?chuàng)建一張存儲(chǔ)賬目信息的表,表頭如下:
創(chuàng)建該表的SQL語句為:
CREATE TABLE IF NOT EXISTS accountTable(
id INTEGER PRIMARY KEY AUTOINCREMENT,
accountType INTEGER,
typeText TEXT,
amount INTEGER
)
該表需要封裝增、刪、改、查接口,代碼如下:
// AccountTable.ets
// 插入數(shù)據(jù)
insertData(account: AccountData, callback: Function) {
// 根據(jù)輸入數(shù)據(jù)創(chuàng)建待插入的數(shù)據(jù)行
const valueBucket: relationalStore.ValuesBucket = generateBucket(account);
this.accountTable.insertData(valueBucket, callback);
}
// 刪除數(shù)據(jù)
deleteData(account: AccountData, callback: Function) {
let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName);
// 根據(jù)id匹配待刪除的數(shù)據(jù)行
predicates.equalTo('id', account.id);
this.accountTable.deleteData(predicates, callback);
}
// 修改數(shù)據(jù)
updateData(account: AccountData, callback: Function) {
const valueBucket: relationalStore.ValuesBucket = generateBucket(account);
let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName);
// 根據(jù)id匹配待刪除的數(shù)據(jù)行
predicates.equalTo('id', account.id);
this.accountTable.updateData(predicates, valueBucket, callback);
}
// 查找數(shù)據(jù)
query(amount: number, callback: Function, isAll: boolean = true) {
let predicates = new relationalStore.RdbPredicates(CommonConstants.ACCOUNT_TABLE.tableName);
if (!isAll) {
predicates.equalTo('amount', amount);
}
this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) = > {
let count: number = resultSet.rowCount;
if (count === 0 || typeof count === 'string') {
console.log(`${CommonConstants.TABLE_TAG}` + 'Query no results!');
callback([]);
} else {
resultSet.goToFirstRow();
const result: AccountData[] = [];
for (let i = 0; i < count; i++) {
let tmp: AccountData = { id: 0, accountType: 0, typeText: '', amount: 0 };
tmp.id = resultSet.getDouble(resultSet.getColumnIndex('id'));
tmp.accountType = resultSet.getDouble(resultSet.getColumnIndex('accountType'));
tmp.typeText = resultSet.getString(resultSet.getColumnIndex('typeText'));
tmp.amount = resultSet.getDouble(resultSet.getColumnIndex('amount'));
result[i] = tmp;
resultSet.goToNextRow();
}
callback(result);
}
});
}
功能實(shí)現(xiàn)
首先創(chuàng)建應(yīng)用主頁(yè)面,主要包括使用Search組件創(chuàng)建的搜索欄和使用List組件創(chuàng)建的賬目清單,如下圖所示:
在打開應(yīng)用時(shí),需要查詢數(shù)據(jù)庫(kù)中存儲(chǔ)的賬目并顯示在主頁(yè)面,因此生命周期函數(shù)aboutToAppear()應(yīng)寫為:
// Mainpage.ets
aboutToAppear() {
this.AccountTable.getRdbStore(() = > { // 獲取數(shù)據(jù)庫(kù)
this.AccountTable.query(0, (result: AccountData[]) = > { // 查詢數(shù)據(jù)庫(kù)中的全部賬目
this.accounts = result;
}, true);
});
}
點(diǎn)擊右上角的“編輯”圖標(biāo),主頁(yè)面變?yōu)槿缦滦Ч?/p>
可以選中需要?jiǎng)h除的賬目,點(diǎn)擊下方“刪除”圖標(biāo)后刪除對(duì)應(yīng)賬目,對(duì)應(yīng)代碼如下:
// Mainpage.ets
deleteListItem() {
for (let i = 0; i < this.deleteList.length; i++) { // 刪除每一項(xiàng)選中的賬目并更新頁(yè)面上的賬目清單
let index = this.accounts.indexOf(this.deleteList[i]);
this.accounts.splice(index, 1);
this.AccountTable.deleteData(this.deleteList[i], () = > {});
}
this.deleteList = [];
this.isEdit = false;
}
搜索欄在鍵入文本并回車時(shí),實(shí)現(xiàn)搜索功能:
// Mainpage.ets
.onSubmit((searchValue: string) = > {
if (searchValue === '') { // 如果搜索欄為空,查找全部賬目
this.AccountTable.query(0, (result: AccountData[]) = > {
this.accounts = result;
}, true);
} else {
this.AccountTable.query(Number(searchValue), (result: AccountData[]) = > { // 查找金額為val的賬目
this.accounts = result;
}, false);
}
})
右下角的“添加”按鈕可以打開一個(gè)自定義彈窗,并在彈窗里新建賬目信息:
// Mainpage.ets
.onClick(() = > {
this.isInsert = true; // 插入模式
this.newAccount = { id: 0, accountType: 0, typeText: '', amount: 0 };
this.dialogController.open();
})
點(diǎn)擊賬目清單中的某個(gè)賬目,也可以打開自定義彈窗,并修改賬目信息:
// Mainpage.ets
selectListItem(item: AccountData) {
this.isInsert = false; // 編輯模式
this.index = this.accounts.indexOf(item);
this.newAccount = {
id: item.id,
accountType: item.accountType,
typeText: item.typeText,
amount: item.amount
};
}
自定義彈窗由使用Tabs組件創(chuàng)建的賬目類別、使用TextInput組件創(chuàng)建的輸入欄和確定按鈕組成,如下圖所示:
點(diǎn)擊“確定”按鈕會(huì)調(diào)用accept()函數(shù),根據(jù)isInsert的值來進(jìn)行賬目的添加或修改,代碼如下:
// Mainpage.ets
accept(isInsert: boolean, newAccount: AccountData): void {
if (isInsert) { // 插入模式,往數(shù)據(jù)庫(kù)插入一個(gè)新賬目
Logger.verbose(`${CommonConstants.INDEX_TAG}`, 'The account inserted is: ' + JSON.stringify(newAccount));
this.AccountTable.insertData(newAccount, (id: number) = > {
newAccount.id = id;
this.accounts.push(newAccount);
});
} else { // 編輯模式,更新當(dāng)前選中的賬目并寫入數(shù)據(jù)庫(kù),刷新頁(yè)面的賬目清單
this.AccountTable.updateData(newAccount, () = > {});
let list = this.accounts;
this.accounts = [];
list[this.index] = newAccount;
this.accounts = list;
this.index = -1;
}
}
審核編輯 黃宇
-
數(shù)據(jù)庫(kù)
+關(guān)注
關(guān)注
7文章
3868瀏覽量
65006 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1987瀏覽量
31078 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3768瀏覽量
17021
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
HarmonyOS開發(fā)案例:【搭建關(guān)系型數(shù)據(jù)庫(kù)】(4)

關(guān)系型數(shù)據(jù)庫(kù)與非關(guān)系數(shù)據(jù)庫(kù)的區(qū)別淺析
HarmonyOS數(shù)據(jù)庫(kù)的相關(guān)資料下載
HarmonyOS關(guān)系型數(shù)據(jù)庫(kù)和對(duì)象關(guān)系數(shù)據(jù)庫(kù)的使用方法
DCS仿真系統(tǒng)的內(nèi)存-關(guān)系型數(shù)據(jù)庫(kù)系統(tǒng)的構(gòu)成
什么是關(guān)系型數(shù)據(jù)庫(kù)
什么是非關(guān)系型數(shù)據(jù)庫(kù)
hbase和關(guān)系型數(shù)據(jù)庫(kù)的區(qū)別

數(shù)據(jù)庫(kù)設(shè)計(jì)開發(fā)案例教程之數(shù)據(jù)庫(kù)設(shè)計(jì)的資料介紹

基于SQLite的鴻蒙的關(guān)系型數(shù)據(jù)庫(kù)使用

OpenHarmony關(guān)系型數(shù)據(jù)庫(kù)概述

關(guān)系型數(shù)據(jù)庫(kù)的基本原理(什么是關(guān)系型數(shù)據(jù)庫(kù))
鴻蒙HarmonyOS開發(fā)實(shí)例:【分布式關(guān)系型數(shù)據(jù)庫(kù)】

評(píng)論