1、一键生成目标对象类型类文件

云数据库支持从端侧或者云侧云函数访问数据库,代码涉及调用云数据库时,需要引入对应云数据库对象类型的类文件。DevEco当前支持为对象类型一键生成类文件,供开发者在端侧或云侧云函数开发时引用,以下为生成端侧对象类型类文件。

  • 在云侧工程中,右击目标对象类型(以Feeding为例),选择“Generate Client Model”。

 

image-20250622215537942

  • 选择生成的Client Model文件存放的端侧目录。

 

image-20250622215544882

  • 点击“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运算组合两个条件并返回两个查询结果的交集。

我们以查询当前宝宝喂养记录为例,需要用到greaterThanOrEqualTolessThanOrEqualTo两个属性来获取当天喂养记录。

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<T extends DatabaseObject>(objectList: T[] | T) 向数据库更新数据,可以更新一条或多条对象数据。
delete<T extends DatabaseObject>(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%')
  }
}

 

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐