简介

dataORM 是一个轻量级 ORM(对象关系映射)库,用于简化本地数据库的操作。提供了高效的数据库访问性能和低内存消耗。dataORM 支持多线程操作、链式调用、备份、升级、缓存等特性等功能。其设计理念是轻量、快速且易于使用,帮助开发者快速构建高性能的应用程序。

效果展示

下载安装

ohpm install @ohos/dataorm --save

OpenHarmony ohpm 环境配置等更多内容,请参考如何安装 OpenHarmony ohpm 包

使用说明

  1. 创建实体类,如Note
import { Id } from '@ohos/dataorm';
import { NotNull } from '@ohos/dataorm';
import { Entity, Columns } from '@ohos/dataorm';
import { Unique } from '@ohos/dataorm';
import { Index } from '@ohos/dataorm';
import { ToMany } from '@ohos/dataorm';
import { ColumnType } from '@ohos/dataorm';
import { ToOne } from '@ohos/dataorm';

@Entity('NOTE')
export class Note {
    @Id()
    @Columns({ columnName: 'ID', types: ColumnType.num })
    id: number;
    @NotNull()
    @Unique()
    @Index(true)
    @Columns({ columnName: 'TEXT', types: ColumnType.str })
    text: string;
    @Columns({ columnName: 'COMMENT', types: ColumnType.str })
    comment: string;
    @Columns({ columnName: 'DATE', types: ColumnType.str })
    date: Date;
    @Columns({ columnName: 'TYPE', types: ColumnType.str })
    type: string;
    @Columns({ columnName: 'MONEYS', types: ColumnType.real })
    moneys: number;

    //todo 类中必须在constructor中声明所有非静态变量,用于反射生成列
    constructor(id?: number, text?: string, comment?: string, date?: Date, types?: string, moneys?: number) {
        this.id = id;
        this.text = text;
        this.comment = comment;
        this.date = date;
        this.type = types;
        this.moneys = moneys;
    }

    getMoneys(): number {
        return this.moneys;
    }

    setMoneys(moneys: number) {
        this.moneys = moneys;
    }

    getId(): number {
        return this.id;
    }

    setId(id: number) {
        this.id = id;
    }

    getText(): string {
        return this.text;
    }

    /** Not-null value; ensure this value is available before it is saved to the database. */
    setText(text: string) {
        this.text = text;
    }

    getComment(): string {
        return this.comment;
    }

    setComment(comment: string) {
        this.comment = comment;
    }

    getDate(): Date {
        return this.date;
    }

    setDate(date: Date) {
        this.date = date;
    }

    getType(): string {
        return this.type;
    }

    setType(types: string) {
        this.type = types;
    }
}
注解对外开放部分:Column、Entity、Id、NotNull、Unique、Index、ToMany、ToOne、JoinEntity、OrderBy、Convert、Embedded、Transient。

可使用注解使用示例及说明:

(1)Id的使用:

1、导入引用

import {Id} from '@ohos/dataorm'; 

2、使用方式:

A、

@Id()
id: number;

B、

@Id({ isPrimaryKey: true ,autoincrement:false})
id: number;

说明:在类属性中使用,定义表主键和键值是否是自增长。A和B的定义方式等同,isPrimaryKey值为true(是表主键),autoincrement值为false(不为自增长)

(2)Entity的使用:

1、导入引用

import {Entity} from '@ohos/dataorm';

2、使用方式:

@Entity('NOTE')
export  class Note {}

说明:在类头使用,定义表表名,如该示例定义为表名为NOTE。

####(3)Column的使用:

1、导入引用

import {Columns} from '@ohos/dataorm';

2、使用方式:

@Columns({ columnName: 'ID', types: ColumnType.num })
text: string;

说明:在类属性中使用,定义在表中的列名和列类型。第一个参数为列名,第二个参数为列的数据类型

(4)NotNull的使用:

1、导入引用

import {NotNull} from '@ohos/dataorm';

2、使用方式:

A、

@NotNull()
text: string;

B、

@NotNull(true)
text: string;

说明:在类属性中使用,定义在表中该列是否可空,当为true值时,在表中该列值为非空值。其中A和B的定义方式等同,该列为非空值。

####(5)Unique的使用:

1、导入引用

import {Unique} from '@ohos/dataorm';

2、使用方式:

A、

@Unique()
text: string;

B、

@Unique(true)
text: string;

说明:在类属性中使用,定义在表中该列是否是唯一值,当为true值时,在表中该列值为唯一值。其中A和B的定义方式等同,该列为唯一值。

####(6)Index的使用:

1、导入引用

import {Index} from '@ohos/dataorm';

2、使用方式:

A、

@Index()
text: string;

B、

@Index(true)
text: string;

c、

@Index(false)
text: string;

说明:在类属性中使用,定义创建索引表的列以及是否是唯一,当为true值时,为唯一。其中A定义为非唯一索引,B的定义为唯一索引,C定义为非唯一索引.A和C的定义等同。

####(7)ToMany的使用

1、导入引用

import {  ToMany } from '@ohos/dataorm';

2、使用方式:

@ToMany({ targetClsName: "Student", joinProperty: [{ name: "ID", referencedName: "TID" }] })
@OrderBy("NAME ASC")
students: Array<Student>

说明:在类属性中使用,定义了目标关系表 targetClsName, 当前要查询的列 name 与外部目标表关联的列名 referencedName ,其中的name的值是目标referencedName的值 , 返回的是目标的表的对象数组。

调用时方式:

  async queryByToManyFunctionTest() {
    this.daoSession = GlobalContext.getContext().getValue("daoSession") as DaoSession;
    this.studentDao = this.daoSession.getBaseDao(Student);
    var teacherId: string[] = ["1"]
    let data = await this.studentDao.queryToManyListByColumnName("students", teacherId)
    data.forEach(element => {
      console.info("-----tonMany-----" + JSON.stringify(element))
    });
  }

说明: 获取目标表的Dao , 调用queryToManyListByColumnName(toManyColumnName: string, arr: string[]), 传入参数toManyColumnName为当前表所创建类的@ToMany下面的变量名,传入参数arr为关联列的查询值。

(8)JoinEntity的使用

1、导入引用

import { JoinEntity } from '@ohos/dataorm';

2、使用方式

@JoinEntity({ entityName: 'JoinManyToDateEntity', targetClsName: 'DateEntity',  sourceProperty: 'ID_TO_MANY', targetProperty: 'ID_DATE' })
@OrderBy("ID DESC")
dateEntityList: Array<DateEntity>

说明:在类属性中使用,定义了联接表之间的关系, entityName 为链接表的实体类名称, targetClsName 目标表的实体类, sourceProperty为连接实体中包含源(当前)实体id的属性的名称 ,targetProperty 为连接实体中包含目标实体id的属性的名称 , 返回的是目标的表的对象数组。

调用时方式:

  async queryByJoinEntityFunctionTest(){
    this.daoSession = GlobalContext.getContext().getValue("daoSession") as DaoSession;
    this.studentDao = this.daoSession.getBaseDao(DateEntity);
    var teacherId: string[] = ["11"]
    let data = await this.studentDao.queryToManyListByColumnName("dateEntityList", teacherId)
    data.forEach(element => {
      console.info("-----JoinEntity-----" + JSON.stringify(element))
    });
  }

说明: 获取目标表的Dao , 调用queryToManyListByColumnName(toManyColumnName: string, arr: string[]), 传入参数toManyColumnName为当前表所创建类的@ToMany下面的变量名,传入参数arr为关联列的查询值。

####(9)ToOne的使用

1、导入引用

import { ToOne } from '@ohos/dataorm';

2、使用方式

@ToOne({ value: 'TID', targetObj: Teacher })
teacher: Teacher

说明:在类属性中使用,定义了当前表 value为关联的列,targetObj 为关链创建的表的类。

调用时方式:

A、

async loadDeep() {
   this.daoSession = GlobalContext.getContext().getValue("daoSession") as DaoSession;
   this.studentDao = this.daoSession.getBaseDao(Student);
   let studentId =         1
   let student: Student = await this.studentDao.loadDeep(studentId);
}

B、

async queryByToOneFunctionTest() {
     this.daoSession = GlobalContext.getContext().getValue("daoSession") as DaoSession;
     this.studentDao = this.daoSession.getBaseDao(Student);
     let columnName = this.studentDao.getPkProperty().columnName
     let entityList = await this.studentDao.queryDeep("WHERE T." + columnName + "=?", ["1"]);
     let entity3: Student = entityList[0];
}

说明: 获取目标表的Dao,拼接查询Sql 作为queryDeep(where: string, selectionArg: string[])的参数去查询。

####(10)Convert的使用

1、导入引用

import { Convert } from '@ohos/dataorm';

2、使用方式

@Convert({ converter: TypeConvert, columnType: ColumnType.str })
images: ArrayList<string>;

说明:在类属性中使用,将对应的属性的集合或者数组,在数据库中存储与取出的操作,@Convert其参数说明:converter:继承PropertyConverter实体,实现其抽象方法;columnType:对应存储到数据库中的类型

PropertyConverter方法介绍:

接口名 功能描述
convertToEntityProperty(databaseValue: Q): P 将数据库数据转化成对应的集合或者数组
convertToDatabaseValue(entityProperty: P): Q 将对象实体中集合或者数组数据转换为数据库存储的类型

####(11)Transient的使用

1、导入引用

import { Transient } from '@ohos/dataorm';

2、使用方式

@Transient()
home: string

说明:Transient注解修饰的属性不会映射到数据库中

####(12)Embedded的使用

1、导入引用

import { Embedded } from '@ohos/dataorm';

2、使用方式

@Embedded({ prefix: "f_", targetClass: Father })
father: Father

说明:Embedded注解:数据实体嵌套的功能,其参数说明,prefix:实体中对应数据库中列名的前缀定义,targetClass:对应嵌套的实体

1. 非加密库在AbilityStage.ts进行初始化
let helper: ExampleOpeHelper = new ExampleOpenHelper(this.context, "notes.db");
helper.setEntities(Note);
let db: Database = await helper.getWritableDb();
this.data.daoSession = new DaoMaster(db).newSession();
2. 加密库在AbilityStage.ets进行初始化
let helper: ExampleOpenHelper = new ExampleOpenHelper(context, "notes.db");
//设定数据加密密钥,加密后不可变更,加密和非加密库暂不能切换(普通数据库不能在设定为加密库,加密库不能变更为普通库,一经生成不可变更)
helper.setEncrypt(true);
//将所有的表 (新增,修改,已存在)加到全局
helper.setEntities(Note);
let db: Database = await helper.getWritableDb();
this.data.daoSession = new DaoMaster(db).newSession();
3. 获取daoSession和Dao对象:在调用页面,如demo中的index页中
private aboutToAppear() {
   daoSess =  GlobalContext.getContext().getValue("daoSession") as DaoSession;
   that.daoSession = daoSess;
   noteDaos = that.daoSession.getBaseDao(Note);
}
4. 添加和移除监听
/*
  *监听
  */
private tabListener(): OnTableChangedListener<any>{
   let that = this;
   return {
     async onTableChanged(t: any, err, action: TableAction) {
       if (action == TableAction.INSERT) {          
         await that.updateNotes();
       } else if(action == TableAction.UPDATE){
         await that.updateNotes();
       } else if(action == TableAction.DELETE){
         await that.updateNotes();
       } else if (action == TableAction.QUERY) {
       }
     }
   }
 }
 /*
  *添加监听
  */
 noteDaos.addTableChangedListener(that.tabListener());
 
 /**
  * 移除监听
  */
 noteDaos.removeTableChangedListener();     
5. 数据库操作
//新增
let date = new Date()
let comment = "Added on " + date.toLocaleString();

let note = new Note();
note.setText(this.noteText);
note.setComment(comment);
note.setDate(new Date());
note.setType(NoteType[NoteType.TEXT]);
noteDaos.insert(note);


//查询
let entityClass = GlobalContext.getContext().getValue(GlobalContext.KEY_CLS) as Record<string, Object>;
let properties = entityClass.Note as Record<string, Property>;
let notesQuery = that.noteDao.queryBuilder().orderAsc(properties.text).build();
this.arr = await this.notesQuery.list();

或者

let entityClass = GlobalContext.getContext().getValue(GlobalContext.KEY_CLS) as Record<string, Object>;
let properties = entityClass.Note as Record<string, Property>;
let query = this.noteDao.queryBuilder().orderAsc(properties.text).buildCursor();
let a = await query.list();


//删除
let entityClass = GlobalContext.getContext().getValue(GlobalContext.KEY_CLS) as Record<string, Object>;
let properties = entityClass.Note as Record<string, Property>;
let deleteQuery = this.noteDao.queryBuilder().where(properties.text.eq("bbb"))
  .buildDelete();
deleteQuery.executeDeleteWithoutDetachingEntities()
6.实体继承

您可以通过使用实体继承模式降低代码编写的冗余度,实现代码的重用,提高程序的可维护性。

1、定义一个基类,把公共属性放在基类中,并使用 @Columns 标记。

import { Columns, ColumnType } from '@ohos/dataorm';

export  class TableBasic {

  @Columns({ columnName: "CREATETIME", types: ColumnType.str })
  createTime: string;

  getCreateTime(): string {
    return this.createTime;
  }
  setCreateTime (createTime: string) {
    this.createTime = createTime;
  }

  constructor(createTime?: string) {
    this.createTime = createTime;
  }
}

2、在需要的业务实体中继承基类。

/**
 * Entity mapped to table "NOTE".
 */
import { Columns, ColumnType, Entity, Id, NotNull } from '@ohos/dataorm'
import { TableBasic } from './test/TableBasic'

@Entity("NOTE", [{ value: "text, date DESC", unique: true }])
export class Note extends TableBasic {
  @Id()
  @Columns({ columnName: "ID", types: ColumnType.num })
  id: number
  @NotNull()
  @Columns({ columnName: "TEXT", types: ColumnType.str })
  text: string
  @Columns({ columnName: "COMMENT", types: ColumnType.str })
  comment: string
  @Columns({ columnName: "DATE", types: ColumnType.str })
  date: string
  @Columns({ columnName: "TYPE", types: ColumnType.str })
  type: string
  @Columns({ columnName: "MONEYS", types: ColumnType.real })
  moneys: number

  constructor(
    id?: number,
    text?: string,
    comment?: string,
    date?: string,
    types?: string,
    moneys?: number,
    createTime?: string,
  ) {
    super(createTime)
    this.id = id
    this.text = text
    this.comment = comment
    this.date = date
    this.type = types
    this.moneys = moneys
  }

}

通过上述示例,得到的NOTE实例中就可以继承createTime属性。

接口说明

接口准备

   // regular SQLite database
   let helper: ExampleOpenHelper = new ExampleOpenHelper(this.context, "notes.db");
   //设定数据加密密钥,加密后不可变更,加密和非加密库暂不能切换(普通数据库不能在设定为加密库,加密库不能变更为普通库,一经生成不可变更)
   helper.setEncrypt(true);
   //将所有的表(新增,修改,已存在)加到全局
   helper.setEntities(Note, Student, Teacher, JoinManyToDateEntity, DateEntity);
   let db: Database = await helper.getWritableDb();
  1. 新增 noteDao.insert(note)
  2. 修改 noteDao.update(note)
  3. 删除 noteDao.delete(note)
  4. 主键删除 noteDao.deleteByKey(id)
  5. 条件删除 noteDao.queryBuilder().where(properties['text'].eq("bbb")).buildDelete()
  6. 查询 noteDao.queryBuilder().list()
  7. 条件查询 noteDao.queryBuilder.whereOr(properties['text'].eq("aaa"), properties['text'].eq("bbb"), properties['text'].eq("ccc")).list()
  8. 缓存查询 noteDao.load(id)
  9. 更新数据,通过从数据库重新加载值来重置实体的所有本地更改的属性 noteDao.refresh(note)
  10. 链式查询 new inquiry().from(Note).query(Note).then((data) => { if(data)this.arr = data; })
  11. 链式条件查询 inquiry().from(Note).eq("ID", 2).querySingle(Note).then((data) => {if(data) this.arr = data; })
  12. 添加监听 noteDao.addTableChangedListener()
  13. 移除监听 noteDao.removeTableChangedListener()
  14. 保存(无则新增,有则更新) noteDao.save(note)
  15. 备份数据库 Migration.backupDB(dbName, tableName, version, context)
  16. 升级数据库 migration.execute(context)
  17. 数据库从资源文件导入数据 executeSqlScript(resourceMgr: any, db: Database, rawFilename: string)
  18. 原始sql语句查询 rawQueries(sql: string, selectionArgs: Array<any>)
  19. ToMany 查询 queryToManyListByColumnName(toManyColumnName: string, arr: string[])
  20. JoinEntity queryToManyListByColumnName(toManyColumnName: string, arr: string[])
  21. ToOne 查询 queryDeep(where: string, selectionArg: string[])

单元测试用例详情见TEST.md

约束与限制

  • DevEco Studio: 4.1 Release(4.1.3.317), SDK: API11 (4.1.0.36)

  • DevEco Studio: 4.0 Release(4.0.3.513), SDK: API10 (4.0.10.10)

  • DevEco Studio 版本:4.0 Release(4.0.3.418),OpenHarmony SDK:(4.0.10.6)

目录结构

|---- dataORM  
|     |---- entry  # 示例代码文件夹
|     |---- library  # dataORM库文件夹
|               |----annotation # 注解相关
|               |----common # 公用类包
|               |----converter # convert注解辅助
|               |----database # 数据库相关
|               |----dbflow # 链式查询
|                   |----base # 链式封装
|                   |----listener # 监听回调
|               |----identityscope # 缓存相关
|               |----internal # 内部调用文件
|               |----query # 查询
|           |---- index.ts  # 对外接口
|     |---- README.MD  # 安装使用方法

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

Logo

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

更多推荐