【鴻蒙開發(fā)】開發(fā)筆記-對象關(guān)系映射數(shù)據(jù)庫
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
一、前言
剛學(xué)習(xí)了對象關(guān)系映射數(shù)據(jù)庫,覺得這個數(shù)據(jù)庫很實(shí)用,所以想把學(xué)習(xí)到的記錄下來,通過文章讓自己的學(xué)習(xí)記憶更深刻。社區(qū)里很多關(guān)于這個的文章,但是我還是想寫一個我自己的。把我自己的理解寫出來,讓社區(qū)的大佬們看一下我有沒有哪些理解錯誤,可以批評指正。
二、概念
HarmonyOS對象關(guān)系映射(Object Relational Mapping,ORM)數(shù)據(jù)庫是一款基于SQLite的數(shù)據(jù)庫框架,屏蔽了底層SQLite數(shù)據(jù)庫的SQL操作,針對實(shí)體和關(guān)系提供了增刪改查等一系列的面向?qū)ο蠼涌?。?yīng)用開發(fā)者不必再去編寫復(fù)雜的SQL語句, 以操作對象的形式來操作數(shù)據(jù)庫,提升效率的同時也能聚焦于業(yè)務(wù)開發(fā)。
以上是官方文檔對這個數(shù)據(jù)庫的描述,我的理解是,這是一個可以存對象的數(shù)據(jù)庫。在關(guān)系型數(shù)據(jù)庫的基礎(chǔ)上,再增加對象這種類型。關(guān)系型數(shù)據(jù)庫只能存基礎(chǔ)類型,在實(shí)際開發(fā)中,我們經(jīng)常會與服務(wù)器進(jìn)行交互。服務(wù)器返回json字符串,之前Android有工具可以轉(zhuǎn)成實(shí)體類,鴻蒙暫時沒看到,但是可以在網(wǎng)上搜索json轉(zhuǎn)實(shí)體類,就可以進(jìn)行json轉(zhuǎn)實(shí)體類。


在沒有學(xué)習(xí)到對象關(guān)系映射數(shù)據(jù)庫之前,我要把一個服務(wù)器返回的實(shí)體類信息進(jìn)行存儲,就需要把返回的實(shí)體類再分解為一個個字段,比如下面Person類。
- public class Person {
- Integer id;
- String name;
- String gender;
- String age;
- }
如果按關(guān)系型數(shù)據(jù)庫來寫的話是這樣的:
- private static final String DB_COLUMN_PERSON_ID = "id";
- private static final String DB_COLUMN_NAME = "name";
- private static final String DB_COLUMN_GENDER = "gender";
- private static final String DB_COLUMN_AGE = "age";
如果類字段少還好,如果多就會很費(fèi)時間,開發(fā)講究效率。那如果是對象型數(shù)據(jù)庫是怎么寫呢,接下來我把這個例子通過對比的方式,讓大家看看對象關(guān)系映射數(shù)據(jù)庫的實(shí)用之處。
三、創(chuàng)建數(shù)據(jù)庫
1.開發(fā)數(shù)據(jù)庫,首先要創(chuàng)建數(shù)據(jù)庫,如果是關(guān)系型數(shù)據(jù)庫,那創(chuàng)建的時候是這么寫的:
a.配置數(shù)據(jù)庫相關(guān)信息,包括數(shù)據(jù)庫的名稱、存儲模式、是否為只讀模式等。
- private static final String DB_NAME = "persondataability.db";//數(shù)據(jù)庫名稱
- private static final String DB_TAB_NAME = "person";//表的名稱
- private static final String DB_COLUMN_PERSON_ID = "id";//字段id
- private static final String DB_COLUMN_NAME = "name";//字段name
- private static final String DB_COLUMN_GENDER = "gender";//字段gender
- private static final String DB_COLUMN_AGE = "age";//字段age
- private static final int DB_VERSION = 1;//數(shù)據(jù)庫版本號
- private StoreConfig storeConfig = StoreConfig.newDefaultConfig(DB_NAME);//配置數(shù)據(jù)庫名稱
- private RdbStore rdbStore;
b.初始化數(shù)據(jù)庫表結(jié)構(gòu)和相關(guān)數(shù)據(jù)。
- private RdbOpenCallback rdbOpenCallback = new RdbOpenCallback() {
- @Override
- public void onCreate(RdbStore rdbStore) {
- //數(shù)據(jù)庫創(chuàng)建時被回調(diào),開發(fā)者可以在該方法中初始化表結(jié)構(gòu),并添加一些應(yīng)用使用到的初始化數(shù)據(jù)。
- rdbStore.executeSql("create table if not exists "
- + DB_TAB_NAME + " ("
- + DB_COLUMN_PERSON_ID +" integer primary key,"
- + DB_COLUMN_NAME + " text not null,"
- + DB_COLUMN_GENDER + " text not null,"
- + DB_COLUMN_AGE + " integer)");
- }
- @Override
- public void onUpgrade(RdbStore rdbStore, int i, int i1) {
- //數(shù)據(jù)庫升級時被回調(diào)
- }
- };
c.創(chuàng)建數(shù)據(jù)庫。
- DatabaseHelper databaseHelper = new DatabaseHelper(this);//DatabaseHelper是數(shù)據(jù)庫操作的輔助類,當(dāng)數(shù)據(jù)庫創(chuàng)建成功后,
- // 數(shù)據(jù)庫文件將存儲在由上下文指定的目錄里。數(shù)據(jù)庫文件存儲的路徑會因指定不同的上下文存在差異。
- rdbStore = databaseHelper.getRdbStore(storeConfig,DB_VERSION,rdbOpenCallback,null);//根據(jù)配置創(chuàng)建或打開數(shù)據(jù)庫。
2.如果是對象關(guān)系型數(shù)據(jù)庫,寫法就簡單很多,如下:
a.創(chuàng)建數(shù)據(jù)庫。開發(fā)者需要定義一個表示數(shù)據(jù)庫的類,繼承OrmDatabase,再通過@Database注解內(nèi)的entities屬性指定哪些數(shù)據(jù)模型類屬于這個數(shù)據(jù)庫。
屬性:
- version:數(shù)據(jù)庫版本號。
- entities:數(shù)據(jù)庫內(nèi)包含的表。
- @Database(entities = {Person.class},version = 1)
- public abstract class PersonOrm extends OrmDatabase {
- }
這里有個小小的坑,有些同學(xué)會出現(xiàn)如下問題:

這里報(bào)錯提示Cannot resolve symbol ‘Database’,那是因?yàn)槲覀儧]有添加一個配置,在當(dāng)前模塊進(jìn)行配置。
如果使用注解處理器的模塊為“com.huawei.ohos.hap”模塊,則需要在模塊的“build.gradle”文件的ohos節(jié)點(diǎn)中添加以下配置:
注意,這里必須添加在當(dāng)前模塊的build.gradle文件,如果是項(xiàng)目的build.gradle文件就沒效果,添加后要進(jìn)行同步,同步按鈕在右上角Sync Now。
- compileOptions{
- annotationEnabled true
- }
這樣就不會報(bào)錯了。
b.創(chuàng)建數(shù)據(jù)表。開發(fā)者可通過創(chuàng)建一個繼承了OrmObject并用@Entity注解的類,獲取數(shù)據(jù)庫實(shí)體對象,也就是表的對象。
屬性:
- tableName:表名。
- primaryKeys:主鍵名,一個表里只能有一個主鍵,一個主鍵可以由多個字段組成。
- foreignKeys:外鍵列表。
- indices:索引列表。

在上面提到的Person.class,其實(shí)就是我們本來用來解析服務(wù)器json數(shù)據(jù)所創(chuàng)建的實(shí)體類,如果要用來存儲數(shù)據(jù)庫,作為數(shù)據(jù)庫的表,就需要進(jìn)行一定的修改,修改如下:
- @Entity(tableName = "person")//設(shè)置表的名稱
- public class Person extends OrmObject {
- @PrimaryKey()//把id作為主鍵
- Integer id;
- String name;
- String gender;
- String age;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getGender() {
- return gender;
- }
- public void setGender(String gender) {
- this.gender = gender;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- }
以上是簡單版本的實(shí)體類修改為數(shù)據(jù)庫實(shí)體對象,也就是表的對象,鴻蒙還提供了幾個實(shí)用的技巧,比如:
1.我們服務(wù)器返回的字段,不一定要存入數(shù)據(jù)庫,可以用"ignoredColumns"表示該字段不加入表的屬性。
2.我們有時候需要兩個字段合起來進(jìn)行查詢,比如姓和名進(jìn)行復(fù)合索引,那么可以用"indices"建立復(fù)合索引。
3.設(shè)置自增的主鍵,這個也是數(shù)據(jù)庫一般都需要的。
在本文例子中,我們添加幾個字段用來展示上面說的技巧,示例如下:
- @Entity(tableName = "person",//設(shè)置表的名稱
- ignoredColumns = {"address"},//設(shè)置不加入表的屬性字段
- indices = {@Index(value = {"firstName","lastName"},name = "name_index",unique = true)})
- //indices 為“firstName”和“lastName”兩個字段建立了復(fù)合索引“name_index”,并且索引值是唯一的
- public class Person extends OrmObject {
- @PrimaryKey(autoGenerate = true)//把id設(shè)為了自增的主鍵。注意只有在數(shù)據(jù)類型為包裝類型時,自增主鍵才能生效
- Integer id;
- String name;
- String gender;
- String age;
- String firstName;
- String lastName;
- String address;//不加入表的屬性
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getGender() {
- return gender;
- }
- public void setGender(String gender) {
- this.gender = gender;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- public String getFirstName() {
- return firstName;
- }
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
- public String getLastName() {
- return lastName;
- }
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- }
c.使用對象數(shù)據(jù)操作接口OrmContext創(chuàng)建數(shù)據(jù)庫。
通過對象數(shù)據(jù)操作接口OrmContext,創(chuàng)建一個別名為“PersonStore”,數(shù)據(jù)庫文件名為“PersonStore.db”的數(shù)據(jù)庫。如果數(shù)據(jù)庫已經(jīng)存在,執(zhí)行以下代碼不會重復(fù)創(chuàng)建。通過context.getDatabaseDir()可以獲取創(chuàng)建的數(shù)據(jù)庫文件所在的目錄。
- // context入?yún)㈩愋蜑閛hos.app.Context,注意不要使用slice.getContext()來獲取context,請直接傳入slice,否則會出現(xiàn)找不到類的報(bào)錯。
- DatabaseHelper databaseHelper = new DatabaseHelper(this);
- //數(shù)據(jù)庫別名為“PersonStore”,數(shù)據(jù)庫文件名稱為“PersonStore.db”,最后傳入的是繼承OrmDatabase的數(shù)據(jù)庫類,這里我一開始寫錯了,以為是實(shí)體類。希望沒人跟我一樣笨
- OrmContext context = databaseHelper.getOrmContext("PersonStore","PersonStore.db", PersonOrm.class);
以上就是對象關(guān)系映射數(shù)據(jù)庫的創(chuàng)建過程,是不是比關(guān)系型數(shù)據(jù)庫要簡單一點(diǎn)呢。數(shù)據(jù)庫創(chuàng)建好了,就需要進(jìn)行增刪改查的操作了,接下來我把關(guān)系型數(shù)據(jù)庫和對象關(guān)系映射數(shù)據(jù)庫的增刪改查都對比一下。為了方便大家對比和學(xué)習(xí),大家可以通過目錄快速查找你想看的內(nèi)容哦。
四、增加數(shù)據(jù)
1.關(guān)系型數(shù)據(jù)庫
封裝了一個插入數(shù)據(jù)的方法,用于調(diào)用。
- /***
- * 向數(shù)據(jù)庫插入數(shù)據(jù)。
- * @param uri 數(shù)據(jù)庫的路徑,傳入路徑,用于判斷是否是正確的數(shù)據(jù)庫
- * @param value 以ValuesBucket存儲的待插入的數(shù)據(jù)。它提供一系列put方法,如putString(String columnName, String values),putDouble(String columnName, double value),用于向ValuesBucket中添加數(shù)據(jù)。
- * @return
- */
- @Override
- public int insert(Uri uri, ValuesBucket value) {
- HiLog.info(LABEL_LOG, "DataAbility insert");
- String path = uri.getLastPath();
- if (!"person".equals(path)){
- HiLog.info(LABEL_LOG,"DataAbility insert path is not matched");
- return -1;
- }
- ValuesBucket valuesBucket = new ValuesBucket();
- valuesBucket.putInteger(DB_COLUMN_PERSON_ID,value.getInteger(DB_COLUMN_PERSON_ID));
- valuesBucket.putString(DB_COLUMN_NAME, value.getString(DB_COLUMN_NAME));
- valuesBucket.putString(DB_COLUMN_GENDER,value.getString(DB_COLUMN_GENDER));
- valuesBucket.putInteger(DB_COLUMN_AGE,value.getInteger(DB_COLUMN_AGE));
- int index = (int) rdbStore.insert(DB_TAB_NAME,valuesBucket);//插入數(shù)據(jù),第一個參數(shù)是數(shù)據(jù)庫的表名,第二個是數(shù)據(jù)
- DataAbilityHelper.creator(this,uri).notifyChange(uri);//通知數(shù)據(jù)庫更新
- return index;
- }
2.對象關(guān)系映射數(shù)據(jù)庫
當(dāng)數(shù)據(jù)庫有變化時,關(guān)系型數(shù)據(jù)庫通過DataAbilityHelper.creator(this,uri).notifyChange(uri);通知數(shù)據(jù)庫更新,uri為數(shù)據(jù)庫的路徑。那對象關(guān)系映射數(shù)據(jù)庫通過什么通知更新呢?通過注冊觀察者。
通過使用對象數(shù)據(jù)操作接口,開發(fā)者可以在某些數(shù)據(jù)上設(shè)置觀察者,接收數(shù)據(jù)變化的通知。

- // 定義一個觀察者類。
- private class CustomedOrmObjectObserver implements OrmObjectObserver {
- @Override
- public void onChange(OrmContext changeContext, AllChangeToTarget subAllChange) {
- // 用戶可以在此處定義觀察者行為
- }
- }
用法:
- CustomedOrmObjectObserver observer = new CustomedOrmObjectObserver();
- context.registerEntityObserver("Person", observer); // 調(diào)用registerEntityObserver方法注冊一個觀察者observer
- context.close();//不需要的時候及時關(guān)閉
- // 當(dāng)以下方法被調(diào)用,并flush成功時,觀察者observer的onChange方法會被觸發(fā)。其中,方法的入?yún)⒈仨殲镻erson類的對象。
- public <T extends OrmObject> boolean insert(T object)
- public <T extends OrmObject> boolean update(T object)
- public <T extends OrmObject> boolean delete(T object)
回到增加數(shù)據(jù)上來,對象關(guān)系映射數(shù)據(jù)庫增加數(shù)據(jù)方法如下:
- private void insert(){
- Person person = new Person();
- person.setName("lili");
- person.setAge("12");
- person.setGender("女");
- OrmContext ormContext = databaseHelper.getOrmContext(DB_ALIAS,DB_NAME,PersonOrm.class);
- if (ormContext.insert(person)){
- //說明插入成功
- }else {
- //說明插入失敗
- }
- ormContext.registerContextObserver(ormContext,observer);
- ormContext.flush();
- ormContext.close();
- }
這個增加數(shù)據(jù)是不是比關(guān)系型數(shù)據(jù)庫要簡單一點(diǎn)呢?而且也比較符合我們的代碼習(xí)慣,直接把實(shí)體對象賦值,傳入就可以了。
五、查詢數(shù)據(jù)
1.關(guān)系型數(shù)據(jù)庫
a.構(gòu)造用于查詢的謂詞對象,設(shè)置查詢條件。
b.指定查詢返回的數(shù)據(jù)列。
c.調(diào)用查詢接口查詢數(shù)據(jù)。
d.調(diào)用結(jié)果集接口,遍歷返回結(jié)果
這里官網(wǎng)給的例子是以下這樣的:
- String[] columns = new String[] {"id", "name", "age", "salary"}; //構(gòu)造用于查詢的謂詞對象
- RdbPredicates rdbPredicates = new RdbPredicates("test").equalTo("age", 25).orderByAsc("salary");//設(shè)置查詢條件,指定查詢返回的數(shù)據(jù)列
- ResultSet resultSet = store.query(rdbPredicates, columns);//調(diào)用查詢接口查詢數(shù)據(jù)
- resultSet.goToNextRow();//調(diào)用結(jié)果集接口,遍歷返回結(jié)果
但是實(shí)際應(yīng)用中,我們一般把關(guān)系型數(shù)據(jù)庫的代碼寫在DataAbility里面,所以這邊查詢封裝的代碼如下:
- /***
- *
- * @param uri 數(shù)據(jù)庫的地址
- * @param columns 構(gòu)造用于查詢的謂詞對象
- * @param predicates 查詢條件
- * @return 返回結(jié)果集
- */
- @Override
- public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {
- RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates,DB_TAB_NAME);//構(gòu)造查詢條件
- ResultSet resultSet = rdbStore.query(rdbPredicates,columns);//調(diào)用查詢接口
- if (resultSet == null){
- HiLog.info(LABEL_LOG,"resultSet is null");
- }
- return resultSet;
- }
那我們要怎么調(diào)用呢?調(diào)用如下:
- private void query() {
- String[] columns = new String[] {DB_COLUMN_PERSON_ID,
- DB_COLUMN_NAME, DB_COLUMN_GENDER, DB_COLUMN_AGE};
- // 構(gòu)造查詢條件
- DataAbilityPredicates predicates = new DataAbilityPredicates();
- predicates.between(DB_COLUMN_AGE, 15, 40);//構(gòu)造查詢條件
- try {
- ResultSet resultSet = databaseHelper.query(Uri.parse(BASE_URI + DATA_PATH),
- columns, predicates);//調(diào)用封裝方法
- if (resultSet == null || resultSet.getRowCount() == 0) {
- HiLog.info(LABEL_LOG, "query: resultSet is null or no result found");
- return;
- }
- resultSet.goToFirstRow();//回到結(jié)果第一行
- do {//開始遍歷結(jié)果
- int id = resultSet.getInt(resultSet.getColumnIndexForName(DB_COLUMN_PERSON_ID));
- String name = resultSet.getString(resultSet.getColumnIndexForName(DB_COLUMN_NAME));
- String gender = resultSet.getString(resultSet.getColumnIndexForName(DB_COLUMN_GENDER));
- int age = resultSet.getInt(resultSet.getColumnIndexForName(DB_COLUMN_AGE));
- HiLog.info(LABEL_LOG, "query: Id :" + id + " Name :" + name + " Gender :" + gender + " Age :" + age);
- } while (resultSet.goToNextRow());
- } catch (DataAbilityRemoteException | IllegalStateException exception) {
- HiLog.error(LABEL_LOG, "query: dataRemote exception | illegalStateException");
- }
- }
2.對象關(guān)系映射數(shù)據(jù)庫
- private void query() {
- OrmContext ormContext = databaseHelper.getOrmContext(DB_ALIAS,DB_NAME,PersonOrm.class);
- OrmPredicates query = ormContext.where(Person.class).equalTo("name", "San");
- List<Person> persons = ormContext.query(query);
- ormContext.flush();
- ormContext.close();
- if (persons.size() == 0) {
- return;
- }
- for (Person person : persons) {
- //循環(huán)輸出結(jié)果
- }
- }
對比起來,對象關(guān)系映射數(shù)據(jù)庫是不是更簡單呢?有種SQL語句的感覺哈哈
六、更新數(shù)據(jù)
1.關(guān)系型數(shù)據(jù)庫
- @Override
- public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {
- RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates,DB_TAB_NAME);
- int index = rdbStore.update(value,rdbPredicates);
- HiLog.info(LABEL_LOG,"update:"+ index);
- DataAbilityHelper.creator(this,uri).notifyChange(uri);
- return index;
- }
怎么調(diào)用呢?
- private void update() {
- DataAbilityPredicates predicates = new DataAbilityPredicates();
- predicates.equalTo(DB_COLUMN_PERSON_ID, 102);
- ValuesBucket valuesBucket = new ValuesBucket();
- valuesBucket.putString(DB_COLUMN_NAME, "ZhangSanPlus");
- valuesBucket.putInteger(DB_COLUMN_AGE, 28);
- try {
- if (databaseHelper.update(Uri.parse(BASE_URI + DATA_PATH), valuesBucket, predicates) != -1) {
- HiLog.info(LABEL_LOG, "update successful");
- }
- } catch (DataAbilityRemoteException | IllegalStateException exception) {
- HiLog.error(LABEL_LOG, "update: dataRemote exception | illegalStateException");
- }
- }
2.對象映射關(guān)系型數(shù)據(jù)庫
- private void update() {
- OrmContext ormContext = databaseHelper.getOrmContext(DB_ALIAS,DB_NAME,PersonOrm.class);
- OrmPredicates predicates = ormContext.where(Person.class);
- predicates.equalTo("age", 29);
- List<Person> persons = ormContext.query(predicates);
- if (persons.size() == 0) {
- new ToastDialog(this).setText("no data not update").show();
- return;
- }
- Person user = persons.get(0);
- ormContext.registerObjectObserver(user, observer);
- user.setFirstName("Li");
- if (ormContext.update(user)) {
- //更新成功
- } else {
- //更新失敗
- }
- ormContext.flush();
- ormContext.close();
- ormContext.unregisterObjectObserver(user, observer);
- }
上面例子提供了兩種更新的應(yīng)用,根據(jù)查詢條件進(jìn)行更新,或是指定某個數(shù)據(jù)項(xiàng)進(jìn)行更新。
對比還是覺得對象映射關(guān)系型數(shù)據(jù)庫要簡單易懂一點(diǎn)。
七、刪除數(shù)據(jù)
1.關(guān)系型數(shù)據(jù)庫
- @Override
- public int delete(Uri uri, DataAbilityPredicates predicates) {
- RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates,DB_TAB_NAME);
- int index = rdbStore.delete(rdbPredicates);
- HiLog.info(LABEL_LOG,"delete"+index);
- DataAbilityHelper.creator(this,uri).notifyChange(uri);
- return index;
- }
調(diào)用方法:
- private void delete() {
- DataAbilityPredicates predicates = new DataAbilityPredicates()
- .equalTo(DB_COLUMN_PERSON_ID, 100);
- try {
- if (databaseHelper.delete(Uri.parse(BASE_URI + DATA_PATH), predicates) != -1) {
- HiLog.info(LABEL_LOG, "delete successful");
- }
- } catch (DataAbilityRemoteException | IllegalStateException exception) {
- HiLog.error(LABEL_LOG, "delete: dataRemote exception | illegalStateException");
- }
- }
2.對象映射關(guān)系數(shù)據(jù)庫
- private void delete() {
- OrmContext ormContext = databaseHelper.getOrmContext(DB_ALIAS,DB_NAME,PersonOrm.class);
- OrmPredicates predicates = ormContext.where(Person.class);
- predicates.equalTo("age", 29);
- List<Person> persons = ormContext.query(predicates);
- if (persons.size() == 0) {
- new ToastDialog(this).setText("no data not delete").show();
- return;
- }
- Person person = persons.get(0);
- if (ormContext.delete(person)) {
- new ToastDialog(this).setText("delete success").show();
- } else {
- new ToastDialog(this).setText("delete fail").show();
- }
- ormContext.flush();
- ormContext.close();
- }
八、小結(jié)
以上就是關(guān)于兩種數(shù)據(jù)庫類型的增刪改查,對比一下,對象映射關(guān)系型數(shù)據(jù)庫相對簡單易懂一些。關(guān)系型數(shù)據(jù)庫我覺得兩個重要的,一個是ValuesBucket 用來構(gòu)建數(shù)據(jù) value, 一個是DataAbilityPredicates 用來構(gòu)建條件predicates。對象映射關(guān)系數(shù)據(jù)庫主要是在于實(shí)體類,比較符合我們和服務(wù)器交互的需要。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)


2012-05-17 11:45:12




