1、一键生成目标对象类型类文件
云数据库支持从端侧或者云侧云函数访问数据库,代码涉及调用云数据库时,需要引入对应云数据库对象类型的类文件。DevEco当前支持为对象类型一键生成类文件,供开发者在端侧或云侧云函数开发时引用,以下为生成端侧对象类型类文件。
- 在云侧工程中,右击目标对象类型(以Feeding为例),选择“Generate Client Model”。
- 选择生成的Client Model文件存放的端侧目录。
- 点击“OK”。指定目录下生成对应对象类型的Client Model文件,后续开发者便可以在端侧代码中方便地引用该Client Model。
import { Feeding } from '../model/Feeding';
2、在端侧工程操作云数据库
云开发服务能力为开发者提供了直接操作云数据库的模块,该模块可以对云数据库进行数据写入、查询、删除等操作。
端侧工程查询云数据库数据分为三步,第一步引入云数据库模块组件;第二步构建查询条件;第三步从存储区获取满足查询条件的数据。
1)引入云数据库模块组件和端侧模型类Feeding。
import { cloudDatabase } from '@kit.CloudFoundationKit';
import { Feeding } from '../model/Feeding';
2)构建查询条件
云数据库模块提供了丰富的谓词查询来构建查询条件,包括以下谓词:
方法 | 说明 |
---|---|
equalTo(fieldName: string, value: FieldType) | 添加实体类中某个字段的值等于指定值的查询条件 |
notEqualTo(fieldName: string, value: FieldType) | 添加实体类中某个字段的值不等于指定值的查询条件 |
beginsWith(fieldName: string, value: FieldType) | 添加实体类中string类型字段值以指定子串开头的查询条件。 |
endsWith(fieldName: string, value: FieldType) | 添加实体类中string类型字段值以指定子串结尾的查询条件。 |
contains(fieldName: string, value: FieldType) | 添加实体类中字符串类型字段值包含指定子字符串的查询条件。 |
greaterThan(fieldName: string, value: FieldType) | 添加实体类字段值大于指定值的查询条件。 |
greaterThanOrEqualTo(fieldName: string, value: FieldType) | 添加实体类字段值大于或等于指定值的查询条件。 |
lessThan(fieldName: string, value: FieldType) | 添加实体类字段值小于指定值的查询条件。 |
lessThanOrEqualTo(fieldName: string, value: FieldType) | 添加实体类字段值小于或等于指定值的查询条件。 |
in(fieldName: string, values: FieldType[]) | 添加实体类字段值包含在指定数组中的查询条件。 |
isNull(fieldName: string) | 添加实体类某字段值为空的查询条件。 |
isNotNull(fieldName: string) | 添加实体类某字段值不为空的查询条件。 |
orderByAsc(fieldName: string) | 按指定字段升序对查询结果进行排序。 |
orderByDesc(fieldName: string) | 按指定字段降序对查询结果进行排序。 |
limit(count: number, offset?: number) | 指定返回的查询结果集中的数据记录条数。如果不设置offset,则默认从首个对象开始获取前count个对象。 |
beginGroup() | 调用此方法是为了放置左括号“(”附加到任何查询条件并将右括号“)”与相同的查询连接起来组合使用。 |
endGroup() | 调用此方法是为了放置右括号“)”附加到任何查询条件并将左括号“(”与相同的查询连接起来组合使用。 |
or() | 使用or运算组合两个条件并返回两个查询结果的并集。 |
and() | 使用and运算组合两个条件并返回两个查询结果的交集。 |
我们以查询当前宝宝喂养记录为例,需要用到greaterThanOrEqualTo
、lessThanOrEqualTo
两个属性来获取当天喂养记录。
condition: cloudDatabase.DatabaseQuery<Feeding> = new cloudDatabase.DatabaseQuery(Feeding);
condition.greaterThanOrEqualTo("startTime", this.currentDateTime.setHours(0, 0, 0, 0)).and().lessThanOrEqualTo("startTime", this.currentDateTime.setHours(23, 59, 59, 999));
3)查询数据
构建符合业务逻辑的查询条件之后,调用云数据库模块提供通过存储区名称初始化云数据库实例。云数据库实例具备以下能力:
方法 | 说明 |
---|---|
query<T extends DatabaseObject>(condition: DatabaseQuery<T>) | 通过查询条件查询数据 |
calculateQuery<T extends DatabaseObject>(condition: DatabaseQuery<T>, fieldName: string, calculate: QueryCalculate) | 从数据库中查询符合条件的数据,并对指定字段进行算术计算。 |
`upsert(objectList: T[] | T)` |
`delete(objectList: T[] | T)` |
// 构建查询条件
const queryCondition = this.condition.greaterThanOrEqualTo("startTime", this.currentDateTime.setHours(0, 0, 0, 0)).and().lessThanOrEqualTo("startTime", this.currentDateTime.setHours(23, 59, 59, 999));
const result = await this.databaseZone.query(queryCondition);
完成的代码:
currentDateTime: Date = new Date();
condition: cloudDatabase.DatabaseQuery<Feeding> = new cloudDatabase.DatabaseQuery(Feeding);
private databaseZone = cloudDatabase.zone("default");@State allFeedingList: Feeding[] = [];// 查询当前喂养记录信息
async queryAllFeeding() {try {// 构建查询条件const queryCondition = this.condition.greaterThanOrEqualTo("startTime", this.currentDateTime.setHours(0, 0, 0, 0)).and().lessThanOrEqualTo("startTime", this.currentDateTime.setHours(23, 59, 59, 999));const result = await this.databaseZone.query(queryCondition);if (result.length > 0) {this.allFeedingList = result;}} catch (error) {// 异常处理this.allFeedingList = [];}
}async aboutToAppear(): Promise<void> {this.queryAllFeeding();
}// 页面
if (this.allFeedingList.length > 0) {List() {ForEach(this.allFeedingList, (item: Feeding) => {ListItem() {Column({ space: 8 }) {Row() {Text(`${item.type}喂养`)Text(`${item.startTime.toLocaleDateString()}`)}.width('100%').height(32).justifyContent(FlexAlign.SpaceBetween)if (item.type === '母乳') {Row() {Text(`左边喂养时长:${item.leftDuration}m`)Text(`右边喂养时长:${item.rightDuration}m`)}.width('100%').justifyContent(FlexAlign.SpaceBetween)}Text(`总喂养时长:${item.totalDuration}m`).width('100%').height(32)}.backgroundColor(0xf2f2f2).padding(12).borderRadius(8)}})}.width('90%').divider({strokeWidth: 2,color: Color.White})
}
4)新增数据
// 新增喂养记录
async insertFeeding(feeding: Feeding) {await this.databaseZone.upsert(feeding);
}
5)删除数据
// 删除数据
async deleteFeeding(feeding: Feeding) {await this.databaseZone.delete(feeding);
}
完整代码:
import { cloudFunction, cloudDatabase } from '@kit.CloudFoundationKit';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { SymbolGlyphModifier } from '@kit.ArkUI';import { Feeding } from '../model/Feeding';interface BabyAge {years: number;months: number;days: number;totalDays: number;
}interface ResponseBody {code: number;desc: string;data: BabyAge
}@Entry
@Component
struct Index {controller: SearchController = new SearchController();@State birthday: string = "";@State callFunctionResult: BabyAge | undefined = undefined;currentDateTime: Date = new Date();condition: cloudDatabase.DatabaseQuery<Feeding> = new cloudDatabase.DatabaseQuery(Feeding);private databaseZone = cloudDatabase.zone("default");@State allFeedingList: Feeding[] = [];@State feeding: Feeding = new Feeding();@State isFeeding: boolean = false;@State startTime: Date = new Date();// 查询当前喂养记录信息async queryAllFeeding() {try {// 构建查询条件const queryCondition = this.condition.greaterThanOrEqualTo("startTime", this.currentDateTime.setHours(0, 0, 0, 0)).and().lessThanOrEqualTo("startTime", this.currentDateTime.setHours(23, 59, 59, 999));const result = await this.databaseZone.query(queryCondition);if (result.length > 0) {this.allFeedingList = result;}} catch (error) {// 异常处理this.allFeedingList = [];}}// 新增喂养记录async insertFeeding(feeding: Feeding) {await this.databaseZone.upsert(feeding);await this.queryAllFeeding();}// 删除数据async deleteFeeding(feeding: Feeding) {try {await this.databaseZone.delete(feeding);await this.queryAllFeeding();} catch (error) {const err: BusinessError = error;this.getUIContext().getPromptAction().showToast({message: err.message})}}async aboutToAppear(): Promise<void> {this.queryAllFeeding();}build() {Column({ space: 10 }) {Text("请先设置宝宝出生日期").fontColor(Color.Grey).height(54)Search({ controller: this.controller, value: this.birthday }).width('90%').height('54vp').searchIcon(new SymbolGlyphModifier($r('sys.symbol.calendar_badge_play')).fontColor([Color.Grey]).fontSize('30fp')).cancelButton({style: CancelButtonStyle.INVISIBLE}).borderRadius('8vp').onClick(() => {CalendarPickerDialog.show({selected: new Date(this.birthday),acceptButtonStyle: {style: ButtonStyleMode.EMPHASIZED},cancelButtonStyle: {fontColor: Color.Grey},onAccept: async (value) => {this.birthday = value.toLocaleDateString();console.info("calendar onAccept:" + JSON.stringify(value))let result: cloudFunction.FunctionResult = await cloudFunction.call({name: 'calculate-baby-age',version: '$latest',timeout: 10 * 1000,data: {birthday: this.birthday}});let body = result.result as ResponseBody;this.callFunctionResult = body.data;}})})if (this.callFunctionResult !== undefined) {Row() {Column({ space: 8 }) {Text(`我已经${this.callFunctionResult.years}岁了 ${this.callFunctionResult.months}月 ${this.callFunctionResult.days}天了~`)Text(`我已经出生${this.callFunctionResult.totalDays}天了~`)}.width('100%')}.width('90%')Button(`${this.isFeeding ? '停止喂养' : '开始喂养'}`).backgroundColor(this.isFeeding ? Color.Orange : Color.Green).onClick(async () => {this.isFeeding = !this.isFeeding;if (this.isFeeding) {this.startTime = new Date();this.feeding.id = this.allFeedingList.length + 1;this.feeding.startTime = this.startTime;} else {this.feeding.totalDuration = new Date().getTime() - this.startTime.getTime();await this.insertFeeding(this.feeding);}})if (this.allFeedingList.length > 0) {List() {ForEach(this.allFeedingList, (item: Feeding) => {ListItem() {Column({ space: 8 }) {Row() {Text(`${item.type}喂养`)Text(`${item.startTime.toLocaleDateString()}`)}.width('100%').height(32).justifyContent(FlexAlign.SpaceBetween)Text(`总喂养时长:${item.totalDuration >= (60 * 1000) ? (item.totalDuration / (60 * 1000)) + 'm' : (item.totalDuration / 1000) + 's'}`).width('100%').height(32)Row() {Button("删除").onClick(async () => {this.getUIContext().getPromptAction().showDialog({title: '温馨提示',message: '确定要删除该喂养记录吗?',buttons: [{text: '取消',color: '#D3D3D3'},{text: '确定',color: '#FF5277'}],}).then(async data => {console.info('showDialog success, click button: ' + data.index);if (data.index === 1) {await this.deleteFeeding(item);}}).catch((err: Error) => {console.info('showDialog error: ' + err);})})}.width('100%')}.backgroundColor(0xf2f2f2).padding(12).borderRadius(8)}})}.width('90%').height(450).divider({strokeWidth: 2,color: Color.White})}}}.width('100%').height('100%')}
}