直接跳到内容

数据库

介绍

数据库模块提供本地持久化能力,当前以 Demo 作为最小示例,演示实体定义、数据源接口与数据源实现。实际业务可按此结构扩展。

设计思路

  • 数据库模块只负责数据的本地读写,不直接给业务层使用。
  • 上层通过 DemoRepository 等仓库访问数据,保证数据入口统一。
  • 详细数据库使用请参考官方文档: https://ibest-orm.ibestservices.com/

实体示例

文件位置:core/database/src/main/ets/entity/DemoEntity.ets

ts
import { Column, ColumnType, CreatedAt, PrimaryKey, Table, UpdatedAt } from "@ibestservices/ibest-orm";

/**
 * @file Demo 表实体定义
 */
@Table({ name: "demo_items" })
export class DemoEntity {
  /**
   * 主键 ID
   */
  @PrimaryKey({ autoIncrement: true })
  id?: number;
  /**
   * 标题
   */
  @Column({ type: ColumnType.TEXT })
  title?: string;
  /**
   * 描述
   */
  @Column({ type: ColumnType.TEXT })
  description?: string;
  /**
   * 创建时间
   */
  @CreatedAt()
  createdAt?: string;
  /**
   * 更新时间
   */
  @UpdatedAt()
  updatedAt?: string;
}

数据源接口示例

文件位置:core/database/src/main/ets/datasource/demo/DemoLocalDataSource.ets

ts
import { DemoEntity } from "../../entity/DemoEntity";

/**
 * @file Demo 数据源接口,定义本地 CRUD 能力
 */
export interface DemoLocalDataSource {
  /**
   * 新增一条 Demo 记录
   * @param {string} title - 标题
   * @param {string} [description] - 描述
   * @returns {Promise<number>} 新建记录主键
   */
  createItem(title: string, description?: string): Promise<number>;

  /**
   * 更新 Demo 记录
   * @param {DemoEntity} entity - 待更新实体
   * @returns {Promise<void>} Promise<void>
   */
  updateItem(entity: DemoEntity): Promise<void>;

  /**
   * 按主键删除 Demo 记录
   * @param {number} id - 记录主键
   * @returns {Promise<void>} Promise<void>
   */
  deleteById(id: number): Promise<void>;

  /**
   * 清空 Demo 表
   * @returns {Promise<number>} 受影响行数
   */
  clearAll(): Promise<number>;

  /**
   * 查询全部 Demo 记录,默认按更新时间倒序
   * @returns {Promise<DemoEntity[]>} Demo 列表
   */
  getAllItems(): Promise<DemoEntity[]>;

  /**
   * 根据主键查询单条记录
   * @param {number} id - 记录主键
   * @returns {Promise<DemoEntity | undefined>} 匹配到的 Demo 或 undefined
   */
  getItemById(id: number): Promise<DemoEntity | undefined>;
}

数据源实现示例

文件位置:core/database/src/main/ets/datasource/demo/DemoLocalDataSourceImpl.ets

ts
import { getORM } from "@ibestservices/ibest-orm";

import { DemoEntity } from "../../entity/DemoEntity";
import { DemoLocalDataSource } from "./DemoLocalDataSource";

/**
 * @file Demo 数据源实现,基于 IBest-ORM 封装 CRUD
 */
export class DemoLocalDataSourceImpl implements DemoLocalDataSource {
  /**
   * 迁移标记,避免重复建表
   */
  private static migrated: boolean = false;
  /**
   * ORM 实例
   */
  private orm = getORM();

  constructor() {
    this.ensureMigrated();
  }

  /**
   * 确保 Demo 表完成迁移
   * @returns {void} 无返回
   */
  private ensureMigrated(): void {
    if (!DemoLocalDataSourceImpl.migrated) {
      this.orm.migrate(DemoEntity);
      DemoLocalDataSourceImpl.migrated = true;
    }
  }

  /**
   * 新增一条 Demo 记录
   * @param {string} title - 标题
   * @param {string} description - 描述
   * @returns {Promise<number>} 新建记录主键
   */
  async createItem(title: string, description: string = ""): Promise<number> {
    const entity: DemoEntity = new DemoEntity();
    entity.title = title;
    entity.description = description;
    return this.orm.insert(entity);
  }

  /**
   * 更新 Demo 记录
   * @param {DemoEntity} entity - 待更新实体
   * @returns {Promise<void>} Promise<void>
   */
  async updateItem(entity: DemoEntity): Promise<void> {
    this.orm.save(entity);
  }

  /**
   * 按主键删除 Demo 记录
   * @param {number} id - 记录主键
   * @returns {Promise<void>} Promise<void>
   */
  async deleteById(id: number): Promise<void> {
    this.orm.deleteById(DemoEntity, id);
  }

  /**
   * 清空 Demo 表
   * @returns {Promise<number>} 受影响行数
   */
  async clearAll(): Promise<number> {
    return this.orm.query(DemoEntity).delete();
  }

  /**
   * 查询全部 Demo 记录并按更新时间倒序
   * @returns {Promise<DemoEntity[]>} Demo 列表
   */
  async getAllItems(): Promise<DemoEntity[]> {
    const list: DemoEntity[] = this.orm.query(DemoEntity).find();
    // 以更新时间/创建时间倒序排列,便于展示最新数据
    return list.sort((left: DemoEntity, right: DemoEntity) => {
      const leftTime: number = new Date(left.updatedAt ?? left.createdAt ?? "").getTime() || 0;
      const rightTime: number = new Date(right.updatedAt ?? right.createdAt ?? "").getTime() || 0;
      return rightTime - leftTime;
    });
  }

  /**
   * 根据主键查询单条记录
   * @param {number} id - 记录主键
   * @returns {Promise<DemoEntity | undefined>} 匹配到的 Demo 或 undefined
   */
  async getItemById(id: number): Promise<DemoEntity | undefined> {
    const result: DemoEntity[] = this.orm.query(DemoEntity).where("id", id).find();
    return result[0];
  }
}

仓库实现示例

文件位置:core/data/src/main/ets/repository/DemoRepository.ets

ts
import { DemoEntity, DemoLocalDataSource, DemoLocalDataSourceImpl } from "database";

/**
 * @file Demo 仓库,衔接业务层与本地数据库
 */
export class DemoRepository {
  /**
   * Demo 本地数据源
   */
  private demoLocalDataSource: DemoLocalDataSource;

  /**
   * 构造函数
   * @param {DemoLocalDataSource} [localDataSource] - 可选的本地数据源
   */
  constructor(localDataSource?: DemoLocalDataSource) {
    this.demoLocalDataSource = localDataSource ?? new DemoLocalDataSourceImpl();
  }

  /**
   * 创建 Demo 记录
   * @param {string} title - 标题
   * @param {string} description - 描述
   * @returns {Promise<number>} 新建记录主键
   */
  async createDemo(title: string, description: string = ""): Promise<number> {
    return this.demoLocalDataSource.createItem(title, description);
  }

  /**
   * 更新 Demo 记录
   * @param {DemoEntity} entity - 待更新实体
   * @returns {Promise<void>} Promise<void>
   */
  async updateDemo(entity: DemoEntity): Promise<void> {
    return this.demoLocalDataSource.updateItem(entity);
  }

  /**
   * 删除指定 ID 的 Demo 记录
   * @param {number} id - 记录主键
   * @returns {Promise<void>} Promise<void>
   */
  async deleteDemo(id: number): Promise<void> {
    return this.demoLocalDataSource.deleteById(id);
  }

  /**
   * 清空全部 Demo 记录
   * @returns {Promise<number>} 受影响行数
   */
  async clearAll(): Promise<number> {
    return this.demoLocalDataSource.clearAll();
  }

  /**
   * 获取所有 Demo 记录
   * @returns {Promise<DemoEntity[]>} Demo 列表
   */
  async getAll(): Promise<DemoEntity[]> {
    return this.demoLocalDataSource.getAllItems();
  }

  /**
   * 根据主键查询单条 Demo 记录
   * @param {number} id - 记录主键
   * @returns {Promise<DemoEntity | undefined>} 匹配到的 Demo 或 undefined
   */
  async getById(id: number): Promise<DemoEntity | undefined> {
    return this.demoLocalDataSource.getItemById(id);
  }
}

ViewModel 使用示例

文件位置:feature/demo/src/main/ets/viewmodel/DatabaseViewModel.ets

下面截取两段常用逻辑,展示如何通过仓库访问数据库。

ts
import { BaseViewModel } from "base";
import { DemoEntity, DemoRepository } from "data";

/**
 * @file 数据库示例页 ViewModel
 */
@ObservedV2
export default class DatabaseViewModel extends BaseViewModel {
  /**
   * Demo 仓库
   */
  private demoRepository: DemoRepository = new DemoRepository();

  /**
   * 保存记录(新增或更新)
   * @returns {Promise<void>} Promise<void>
   */
  async save(): Promise<void> {
    await this.runWithLoading(async (): Promise<void> => {
      if (this.editingId > 0) {
        await this.updateById(this.editingId);
      } else {
        await this.demoRepository.createDemo(this.titleInput, this.descInput);
      }
      this.resetInputs();
      await this.fetchList();
    });
  }

  /**
   * 删除指定记录
   * @param {number} id - 记录主键
   * @returns {Promise<void>} Promise<void>
   */
  async delete(id: number): Promise<void> {
    if (!id) {
      return;
    }
    await this.runWithLoading(async (): Promise<void> => {
      await this.demoRepository.deleteDemo(id);
      if (this.editingId === id) {
        this.resetInputs();
      }
      await this.fetchList();
    });
  }

  /**
   * 更新指定 ID 的记录
   * @param {number} id - 记录主键
   * @returns {Promise<void>} Promise<void>
   */
  private async updateById(id: number): Promise<void> {
    const entity: DemoEntity = new DemoEntity();
    entity.id = id;
    entity.title = this.titleInput.trim();
    entity.description = this.descInput.trim();
    await this.demoRepository.updateDemo(entity);
  }
}

与数据层的关系

  • 数据库模块不直接给业务层使用。
  • 业务通过 DemoRepository 访问数据库数据。
  • Repository 统一对外提供业务语义方法,保持依赖收敛。

新增表的做法

如果要新增表,建议按 Demo 的结构来做:

  1. core/database/src/main/ets/datasource/ 下新增一个与表名一致的文件夹。
  2. 在该文件夹内编写数据源接口与实现(参考 Demo 的接口与实现)。
  3. entity/ 下新增对应实体类。
  4. core/database/Index.ets 中补充导出,保证外部可以统一引入。
  5. 在 data 层新增对应 Repository,对外提供业务语义方法。

注意事项

  • Demo 只是示例,真实业务请按需要扩展实体与数据源。
  • 数据库能力与完整使用方法请参考 IBest-ORM 官方文档。