写点什么

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

作者:TiAmo
  • 2022-10-25
    江苏
  • 本文字数:5345 字

    阅读完需:约 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的路径")}
复制代码

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


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 所示。


图 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);
复制代码

分别利用两种方式进行数据更新,更新后的结果如图 6 所示。


(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 删除数据后的结果显示

用户头像

TiAmo

关注

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

还未添加个人简介

评论

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