写点什么

鸿蒙开发实例|对象关系映射数据库

作者:TiAmo
  • 2022-12-09
    江苏
  • 本文字数:5506 字

    阅读完需:约 18 分钟

鸿蒙开发实例|对象关系映射数据库

HarmonyOS 应用数据管理不仅支持单设备的各种结构化数据的持久化,还支持跨设备之间数据的同步、共享及搜索功能,因此,开发者基于 Harmony OS 应用数据管理功能,能实现应用程序数据在不同终端设备之间的无缝衔接,从而保证用户在跨设备使用数据时所用数据的一致性。

HarmonyOS 对象关系映射数据库是 HarmonyOS 中的本地数据库之一,是在 SQLite 数据库的基础上提供的一个抽象层。它屏蔽了底层 SQLite 数据库的 SQL 操作,将实例对象映射到关系上,并提供增、删、改、查等一系列面向对象的接口,使应用程序使用操作实例对象的语法来操作关系型数据库,因此,开发者可以不必编写那些复杂的 SQL 语句,从而既可以提升效率也能聚焦于业务开发。HarmonyOS 中对象关系映射数据库的运作机制如图 1 所示。

从图 1 可以看出,对象关系映射数据库的 3 个主要组件包括:

(1) 数据库: 通过 @Database 注解,且继承自 OrmDatabase 的类,对应关系型数据库。

(2) 实体对象: 通过 @Entity 注解,且继承自 OrmObject 的类,对应关系型数据库中的表。

(3) 对象数据操作接口: 包括数据库操作的入口 OrmContext 类和谓词接口(OrmPredicate)等。


图 1 对象关系映射数据库的运作机制

创建 Phone 设备下的 Java 模板新项目。在进行开发之前,首先要进行 build.gradle 文件的配置,否则无法识别相关数据库的类的包。

一般情况下,使用的注解处理器的模块为 com.huawei.ohos.hap 模块,需要在模块的 build.gradle 文件的 ohos 节点中添加以下配置,代码如下:

compileOptions{    annotationEnabled true    }
复制代码

如果使用注解处理器的模块为 com.huawei.ohos.library,则需要在模块的 build.gradle 文件 dependencies 节点中配置注解处理器,此外,还需要在本地的 HUAWEI SDK 中找到 orm_annotations_java.jar、orm_annotations_processor_java.jar 和 javapoet_java.jar 这 3 个 jar 包的对应目录,并将这 3 个 jar 包的路径导入,代码如下:

dependencies {    compile files("ohos.jar的路径","orm_annotations_java.jar的路径","orm_annotations_processor_java.jar的路径","javapoet_java.jar的路径")    annotationProcessor files("orm_annotations_java.jar的路径","orm_annotations_processor_java.jar的路径","javapoet_java.jar的路径")}
复制代码

如果使用注解处理器的模块为 java-library,则还需要导入 ohos.jar 的路径,具体代码如下:

dependencies {    compile files("ohos.jar的路径","orm_annotations_java.jar的路径","orm_annotations_processor_java.jar的路径","javapoet_java.jar的路径")    annotationProcessor files("orm_annotations_java.jar的路径","orm_annotations_processor_java.jar的路径","javapoet_java.jar的路径")}
复制代码

配置完成之后,就可以开始新建数据库并对其进行操作了,具体步骤如下。

01、新建数据库及属性配置

创建数据库时,首先需要定义一个表示数据库的类,继承 OrmDatabase,再通过 @Database 注解内的 entities 属性指定哪些数据模型类属于这个数据库,version 属性指明数据库版本号。

在本例中,首先新建一个数据库类 BookStore.java,选择 entry→src→main→com.huawei.ormdb,右击选择并新建 Class,命名为 BookStore,如图 2 所示。


图 2 新建一个数据库类

数据库类 BookStore.java 包含了 User 和 Book 两个表,版本号为 1,将数据库类设置为虚类。具体代码如下:

import ohos.data.orm.OrmDatabase;import ohos.data.orm.annotation.Database; @Database(entities = {User.class, Book.class}, version = 1)public abstract  class BookStore extends OrmDatabase {}
复制代码

02、构造数据表

构造数据表,即创建数据库实体类并配置对应的属性(如对应表的主键、外键等)。可通过创建一个继承了 OrmObject 并用 @Entity 注解的类,获取数据库实体对象,也就是表的对象。需要注意的是,数据表必须与其所在的数据库在同一个模块中。以新建的 User 表为例,新建的 User 类与 BookStore 类位于同一模块下,相应的目录如图 3 所示。


图 3 BookStore 数据库与 User 表位于同一模块

具体的构建过程代码如下:

//新建User表import ohos.data.orm.OrmObject;import ohos.data.orm.annotation.Entity;import ohos.data.orm.annotation.Index;import ohos.data.orm.annotation.PrimaryKey;@Entity(tableName = "user", ignoredColumns = {"ignoreColumn1", "ignoreColumn2"},indices = {@Index(value = {"firstName", "lastName"}, name = "name_index", unique = true)})public class User extends OrmObject {    //此处将userId设为了自增的主键。注意只有在数据类型为包装类型时,自增主键才能生效。    @PrimaryKey(autoGenerate = true)    private Integer userId;    private String firstName;    private String lastName;    private int age;    private double balance;    private int ignoreColumn1;    private int ignoreColumn2;     //设置字段的getter和setter方法,此处仅给出示例,读者可以根据所设置的属性自行补全方法    public void setBalance(double balance) {        this.balance = balance;    }    ...     public Integer getUserId() {        return userId;    }    ...}
复制代码

在新建的 User 类中进行属性配置,tableName = "user"即在对应数据库内的表名为 user,indices 为属性列表,@Index 注解的内容对应数据表索引的属性,本例中 indices 为 firstName 和 lastName 两个字段建立了复合索引,索引名为 name_index,并且索引值是唯一的。ignoreColumns 表示该字段不需要添加到 user 表的属性中,即类中定义的 ignoreColumn1 和 ignoreColumn2 不属于 user 表的属性。被 @PrimaryKey 注解的变量对应数据表的主键,一个表里只能有一个主键,在本例的 user 表中,将 userId 设为自增的主键。

数据库内还包含了 Book 表,Book 表的构建和对其操作的实现过程同 User 表相同,具此处不再赘述其体实现。

03、创建数据库

在 MainAbilitySlice 的 onStart()方法中完成数据库的创建,使用对象数据操作接口 OrmContext 创建数据库,实现代码如下

public void onStart(Intent intent) {   super.onStart(intent);   super.setUIContent(ResourceTable.Layout_ability_main); //使用对象数据操作接口OrmContext创建数据库   DatabaseHelper helper = new DatabaseHelper(this);   OrmContext context = helper.getOrmContext("BookStore", "BookStore.db", BookStore.class); //对数据库进行操作   //增加数据     ...    //查询数据     ...    //修改数据     ...    //删除数据     ...}
复制代码

与构建关系型数据库不同的是,此处 new DatabaseHelper(context)方法中 context 的入参类型为 ohos.app.Context,必须直接传入 slice 而不能使用 slice.getContext()获取 context,否则会出现找不到类的报错。到这里,就成功创建了一个别名为 BookStore 且数据库文件名为 BookStore.db 的数据库。如果数据库已经存在,则执行上述代码并不会重复建库。通过 context.getDatabaseDir()可以获取创建的数据库文件所在的目录。

04、数据操作

对象数据操作接口 OrmContext 提供了对数据库进行增、删、改、查的一系列方法,接下来进行详细介绍。

(1)增加数据 。

例如,在名为 user 的表中,新建一个 User 对象并设置其属性。OrmContext 提供 insert()方法将对象插入数据库。执行完 insert()方法后,数据被保存在内存中,只有在 flush()被调用后才会将数据持久化到数据库中。以 HiLog 形式显示插入数据后的 user 表,如图 4 所示。此处涉及对数据库的查询操作,将在稍后进行详细讲解。具体代码如下:

//增加数据 //新建User对象User user = new User();//设置对象属性user.setUserId(0);user.setFirstName("aa");user.setLastName("AA");user.setAge(22);user.setBalance(120.51); //再新建两个User对象,设置属性后将其持久化到数据库中,此处读者可以自行添加代码...//将新建对象插入并持久化到数据库中boolean isSuccessed = context.insert(user);isSuccessed = context.flush(); //以HiLog形式显示新增数据后的user表,以userID升序显示HiLogLabel logLabel = new HiLogLabel(HiLog.LOG_APP,0,"OrmDB");String s = new String("userID");s = s.concat(" firstName");s = s.concat(" lastName");s = s.concat(" age");s = s.concat(" balance");HiLog.fatal(logLabel,"显示插入数据后的user表:");HiLog.fatal(logLabel,s); //查询数据OrmPredicates query = context.where(User.class).orderByAsc("userID");List<User> users = context.query(query);int i = 0;while (i != users.size()) {            int id = users.get(i).getUserId();            String s1 = "\t" + id + "\t\t";            s1 = s1.concat(users.get(i).getFirstName() + "\t");            s1 = s1.concat("\t\t" + users.get(i).getLastName());            s1 = s1.concat("\t " + users.get(i).getAge() + "\t");            s1 = s1.concat(" " + users.get(i).getBalance());            HiLog.fatal(logLabel, s1);            i = i + 1;}
复制代码


(2) 查询数据。

OrmContext 提供 query()方法查询满足指定条件的对象实例。例如,在 user 表中查询 age=22 的对象,在查询之前,依旧需要先设置谓词 query1,利用 query()方法查找 user 表中满足 query1 的数据,得到一个 User 的列表 user1,遍历 user1,获取 user1 中各个对象的属性值,实现代码如下:

//查询age=22的数据并显示 //设置谓词OrmPredicates query1 = context.where(User.class).equalTo("age", "22");//查询List<User> users1 = context.query(query1); //将查询结果以HiLog形式显示HiLogLabel logLabel1 = new HiLogLabel(HiLog.LOG_APP,0,"OrmDB");HiLog.fatal(logLabel1,"显示user表中age值为22的数据:");HiLog.fatal(logLabel1,s);i = 0;while (i != users1.size()){     int id = users1.get(i).getUserId();     String s1 = "\t" + id +"\t\t";     s1 = s1.concat(users1.get(i).getFirstName()+"\t");     s1 = s1.concat("\t\t"+users1.get(i).getLastName());     s1 = s1.concat("\t "+users1.get(i).getAge()+"\t");     s1 = s1.concat(" "+users1.get(i).getBalance());     HiLog.fatal(logLabel1,s1);     i = i + 1;}
复制代码


图 5 查询 user 表中 age=22 的数据

(3) 修改数据。

修改数据包括两种方式,一种是通过直接传入 OrmObject 对象的接口来更新数据,需要先从表中查到需要更新的结果对象列表,然后修改选定对象的值,再调用更新接口将数据持久化到数据库中。例如,将 user 表中 age=39 的数据的 firstName 更新为 sd,需要先查找 user 表中对应的数据,得到一个结果列表,然后选择列表中需要更新的 User 对象,设置更新值,并调用 update 接口传入被更新的 User 对象。最后调用 flush 接口将数据持久化到数据库中。具体代码如下:

//更新数据OrmPredicates predicates = context.where(User.class);predicates.equalTo("age", 39);//获取满足条件的数据集List<User> users2 = context.query(predicates);//选定要更新的数据User userUD = users2.get(0);//设置更新userUD.setFirstName("sd");context.update(userUD);context.flush(); HiLog.fatal(logLabel, "显示更新数据后的user表:");HiLog.fatal(logLabel, s);query = context.where(User.class).orderByAsc("userID");users = context.query(query);i = 0;while (i != users.size()) {     int id = users.get(i).getUserId();     String s1 = "\t" + id + "\t\t";     s1 = s1.concat(users.get(i).getFirstName() + "\t");     s1 = s1.concat("\t\t" + users.get(i).getLastName());     s1 = s1.concat("\t " + users.get(i).getAge() + "\t");     s1 = s1.concat(" " + users.get(i).getBalance());     HiLog.fatal(logLabel, s1);i = i + 1;}
复制代码

另一种方式,可以通过传入谓词的接口来更新和删除数据,方法与 OrmObject 对象的接口类似,只是无须 flush 就可以将数据持久化到数据库中。通过这种方式将 user 表中 age=39 的数据的 firstName 更新为 sd,具体代码如下:

//使用valuesBucket来改变数据ValuesBucket valuesBucket = new ValuesBucket();valuesBucket.putString("firstName", "sd");OrmPredicates update = context.where(User.class).equalTo("age", 39);context.update(update, valuesBucket);
复制代码

(4) 删除数据。

同修改数据一样,也包括两种方式。区别只是删除数据不需要更新对象的值。这里通过直接传入 OrmObject 对象的接口删除数据的方式删除满足 firstName="aa"的第一个 User 对象,并用 flush 接口将数据持久化到数据库中,代码如下

//删除满足firstName = "aa"的第一个对象OrmPredicates del = context.where(User.class).equalTo("firstName", "aa");List<User> usersdel = context.query(del);User userd = usersdel.get(0);context.delete(userd);context.flush();HiLog.fatal(logLabel, "显示删除数据后的user表:");HiLog.fatal(logLabel, s);query = context.where(User.class).orderByAsc("userID");users = context.query(query);i = 0;while (i != users.size()) {     int id = users.get(i).getUserId();     String s1 = "\t" + id + "\t\t";     s1 = s1.concat(users.get(i).getFirstName() + "\t");     s1 = s1.concat("\t\t" + users.get(i).getLastName());s1 = s1.concat("\t " + users.get(i).getAge() + "\t");     s1 = s1.concat(" " + users.get(i).getBalance());     HiLog.fatal(logLabel, s1);     i = i + 1;}
复制代码

显示删除数据后的表,如图 7 所示。


 图 7 删除数据后的结果显示

发布于: 刚刚阅读数: 3
用户头像

TiAmo

关注

有能力爱自己,有余力爱别人! 2022-06-16 加入

还未添加个人简介

评论

发布
暂无评论
鸿蒙开发实例|对象关系映射数据库_华为_TiAmo_InfoQ写作社区