HarmonyOS采用SQLite作为数据存储的标准配置。编写SQLite代码既繁琐又极易出错,因此HarmonyOS提供了一款基于SQLite数据库框架的对象关系映射(Object Relational Mapping, ORM)数据库作为访问SQLite数据库的高级封装。ORM数据库屏蔽了底层SQLite数据库的SQL操作,针对实体和关系提供了增删改查等一系列面向对象的操作接口,极大地降低了数据库应用程序的开发难度。此外,ORM数据库也提供包括数据库创建、升级等常用功能。
___________________________________________________
| Application |
|___________________________________________________|
^ ^
| | Read entity from database \ Entity
| | Save entity into database / |
OrmPredicate \ | __v__ |
> API | ORM | OrmObject
OrmContext / | |_____|
| ^
| |
________________v________v_________________________
| SQLite |
|___________________________________________________|
ORM包括三个重要组件:
一个Entity对应数据库中的一张表。Entity类是SQLite表结构对Java类的映射,在Java中被看作是一个Model类,用于对数据库中的数据进行建模。其中:
OrmContext用于表示对数据库中的表所做的操作,具体包括:
@Database注解告诉系统这是一个ORM数据库对象,如:
@Database(entities={NoteEntity.class},version=1) public abstract class NoteDatabase extends OrmDatabase {...}
entities:指定该数据库包含哪些实体,多个实体以逗号隔开
version:指定数据库的版本号,作为以后数据库升级的依据
数据库类需要继承自OrmDatabase抽象类,并结合OrmContext接口完成创建:
DatabaseHelper databaseHelper = new DatabaseHelper(...); OrmContext ormContext = databaseHelper.getOrmContext( "NoteDB", "note.db", NoteDatabase.class);
OrmMigration类用于数据库的升降级。
_________________
| OrmDatabase |
|-----------------| _________________________
| DatabaseHelper |-->| NoteDB |
| OrmContext | | _____________________ |
|_________________| | | t_note | | ^
| |_____________________| | |
_________________ | |id|title|content|date| | OrmMigration
| Entity | | |__|_____|_______|____| | |
|-----------------| | |__|_____|_______|____| | v
| Integer id | | |__|_____|_______|____| |
| String title |---->|__|_____|_______|____| |
| String content | ^ |_________________________|
| long date | |
|_________________| |
|
OrmContext
OrmPredicate
在entry\build.gradle中启用注解:
... ohos { ... compileOptions { annotationEnabled true } ... } ...
创建entity包:
com.hostest.orm
New
Package
com.hostest.orm.entity
创建NoteEntity类:
entity
New
Java Class
NoteEntity (Class)
在entry\src\main\java\com\hostest\orm\entity\NoteEntity.java中添加代码:
@Entity(tableName = "t_note") public class NoteEntity extends OrmObject { @PrimaryKey(autoGenerate = true) private Integer id; private String title; private String content; private long date; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public long getDate() { return date; } public void setDate(long date) { this.date = date; } }
创建database包:
com.hostest.orm
New
Package
com.hostest.orm.database
创建NoteDatabase类:
database
New
Java Class
NoteDatabase (Class)
在entry\src\main\java\com\hostest\orm\database\NoteDatabase.java中添加代码:
@Database(entities = NoteEntity.class, version = 1) public abstract class NoteDatabase extends OrmDatabase { }
创建dao包:
com.hostest.orm
New
Package
com.hostest.orm.dao
创建NoteDao接口:
dao
New
Java Class
NoteDao (Interface)
在entry\src\main\java\com\hostest\orm\dao\NoteDao.java中添加代码:
public interface NoteDao { boolean insert(NoteEntity noteEntity); boolean delete(int id); boolean update(NoteEntity noteEntity); List<NoteEntity> query(); NoteEntity query(int id); }
创建NoteDaoImpl类:
dao
New
Java Class
NoteDaoImpl (Class)
在entry\src\main\java\com\hostest\orm\dao\NoteDaoImpl.java中添加代码:
public class NoteDaoImpl implements NoteDao { @Override public boolean insert(NoteEntity noteEntity) { return false; } @Override public boolean delete(int id) { return false; } @Override public boolean update(NoteEntity noteEntity) { return false; } @Override public List<NoteEntity> query() { return null; } @Override public NoteEntity query(int id) { return null; } }
为NoteDaoImpl类添加OrmContext成员,并在构造函数中完成初始化:
public class NoteDaoImpl implements NoteDao { private OrmContext ormContext; public NoteDaoImpl(Context contex) { ormContext = (new DatabaseHelper(contex)).getOrmContext( "NoteDB", "note.db", NoteDatabase.class); } ... }
public class NoteDaoImpl implements NoteDao { private OrmContext ormContext; public NoteDaoImpl(Context contex) { ormContext = (new DatabaseHelper(contex)).getOrmContext( "NoteDB", "note.db", NoteDatabase.class); } @Override public boolean insert(NoteEntity noteEntity) { ormContext.insert(noteEntity); return ormContext.flush(); } @Override public boolean delete(int id) { OrmPredicates ormPredicates = ormContext.where( NoteEntity.class).equalTo("id", id); List<NoteEntity> noteEntities = ormContext.query(ormPredicates); NoteEntity deletedNoteEntity = noteEntities.get(0); ormContext.delete(deletedNoteEntity); return ormContext.flush(); } @Override public boolean update(NoteEntity noteEntity) { OrmPredicates ormPredicates = ormContext.where( NoteEntity.class).equalTo("id", noteEntity.getId()); List<NoteEntity> noteEntities = ormContext.query(ormPredicates); NoteEntity updatedNoteEntity = noteEntities.get(0); updatedNoteEntity.setTitle(noteEntity.getTitle()); updatedNoteEntity.setContent(noteEntity.getContent()); updatedNoteEntity.setDate(noteEntity.getDate()); ormContext.update(updatedNoteEntity); return ormContext.flush(); } @Override public List<NoteEntity> query() { OrmPredicates ormPredicates = ormContext.where( NoteEntity.class).greaterThan("id", 0); List<NoteEntity> noteEntities = ormContext.query(ormPredicates); return noteEntities; } @Override public NoteEntity query(int id) { OrmPredicates ormPredicates = ormContext.where( NoteEntity.class).equalTo("id", id); List<NoteEntity> noteEntities = ormContext.query(ormPredicates); NoteEntity queriedNoteEntity = noteEntities.get(0); return queriedNoteEntity; } }
添加编辑页面:
com.hostest.orm
New
Ability
Empty Page Ability
NoteInfoAbility
在entry\src\main\resources\base\graphic目录下创建background_save.xml文件,为“保存”按钮定义背景样式:
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <corners ohos:radius="100"/> <solid ohos:color="#00a2e8"/> </shape>
在entry\src\main\resources\base\layout\ability_note_info.xml中设计详情页面布局:
<DependentLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent"> <TextField ohos:id="$+id:tfTitle" ohos:height="match_content" ohos:width="match_parent" ohos:margin="20vp" ohos:multiple_lines="true" ohos:basement="#808080" ohos:hint="填写标题" ohos:text_size="24fp" /> <TextField ohos:id="$+id:tfContent" ohos:height="match_content" ohos:width="match_parent" ohos:below="$id:tfTitle" ohos:left_margin="20vp" ohos:right_margin="20vp" ohos:multiple_lines="true" ohos:hint="编辑内容" ohos:text_size="22fp" /> <Button ohos:id="$+id:btnSave" ohos:height="50vp" ohos:width="match_parent" ohos:padding="10vp" ohos:align_parent_bottom="true" ohos:margin="20vp" ohos:background_element="$graphic:background_save" ohos:text="保存" ohos:text_size="24fp" ohos:text_color="#ffffff" /> </DependentLayout>
在entry\src\main\java\com\hostest\orm\slice\NoteInfoAbilitySlice.java中为NoteInfoAbilitySlice类增加属性:
public class NoteInfoAbilitySlice extends AbilitySlice { private NoteDao noteDao; private TextField tfTitle; private TextField tfContent; private Button btnSave; ... }
在NoteInfoAbilitySlice类中为“保存”按钮添加点击事件处理:
public class NoteInfoAbilitySlice extends AbilitySlice { ... @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_note_info); noteDao = new NoteDaoImpl(this); tfTitle = (TextField)findComponentById(ResourceTable.Id_tfTitle); tfContent = (TextField)findComponentById(ResourceTable.Id_tfContent); btnSave = (Button)findComponentById(ResourceTable.Id_btnSave); btnSave.setClickedListener(component -> { NoteEntity noteEntity = new NoteEntity(); noteEntity.setTitle(tfTitle.getText()); noteEntity.setContent(tfContent.getText()); noteEntity.setDate(System.currentTimeMillis()); if (noteDao.insert(noteEntity)) new ToastDialog(this) .setText("保存成功") .setAlignment(LayoutAlignment.CENTER) .show(); else new ToastDialog(this) .setText("保存失败") .setAlignment(LayoutAlignment.CENTER) .show(); }); } ... }
在MainAbilitySlice类中为主页面文本添加点击事件处理,点击该文本跳转到详情页面:
public class MainAbilitySlice extends AbilitySlice { @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); findComponentById(ResourceTable.Id_text_helloworld) .setClickedListener(component -> { Intent intentNoteInfo = new Intent(); intentNoteInfo.setOperation(new Intent.OperationBuilder() .withDeviceId("") .withBundleName("com.hostest.orm") .withAbilityName("com.hostest.orm.NoteInfoAbility") .build()); startAbility(intentNoteInfo); }); } ... }
运行效果如下图所示:
在entry\src\main\resources\base\graphic目录下创建background_button.xml文件,为“+”按钮定义背景样式:
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="oval"> <solid ohos:color="#00a2e8"/> </shape>
在entry\src\main\resources\base\layout\ability_main.xml中设计列表页面布局:
<DependentLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent"> <ListContainer ohos:id="$+id:lc" ohos:height="match_parent" ohos:width="match_parent" ohos:margin="10vp" /> <Button ohos:id="$+id:btn" ohos:height="50vp" ohos:width="50vp" ohos:align_parent_right="true" ohos:align_parent_bottom="true" ohos:margin="20vp" ohos:background_element="$graphic:background_button" ohos:text="+" ohos:text_size="30fp" ohos:text_color="#ffffff" /> </DependentLayout>
将删除图片delete.png放到entry\src\main\resources\base\media目录下:
在entry\src\main\resources\base\layout目录下创建note_item.xml文件,定义列表项布局:
<DependentLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_content" ohos:width="match_parent" ohos:margin="10vp"> <Text ohos:id="$+id:txtTitle" ohos:height="match_content" ohos:width="match_parent" ohos:multiple_lines="true" ohos:text_size="26fp" /> <Text ohos:id="$+id:txtContent" ohos:height="match_content" ohos:width="match_parent" ohos:below="$id:txtTitle" ohos:top_margin="10vp" ohos:multiple_lines="true" ohos:text_size="20fp" ohos:text_color="#808080" /> <Text ohos:id="$+id:txtDate" ohos:height="match_content" ohos:width="match_parent" ohos:below="$id:txtContent" ohos:top_margin="10vp" ohos:text_size="18fp" ohos:text_color="#c3c3c3" /> <Text ohos:id="$+id:txtId" ohos:height="match_content" ohos:width="match_content" ohos:align_parent_right="true" ohos:align_bottom="$id:txtDate" ohos:text_size="18fp" ohos:text_color="#c3c3c3" /> <Text ohos:height="2vp" ohos:width="match_parent" ohos:below="$id:txtDate" ohos:top_margin="5vp" ohos:background_element="#808080" /> <Image ohos:id="$+id:img" ohos:height="match_content" ohos:width="match_content" ohos:align_parent_right="true" ohos:align_parent_top="true" ohos:image_src="$media:delete" /> </DependentLayout>
添加provider包和NoteItemProvider类,为列表容器提供表项组件:
public class NoteItemProvider extends BaseItemProvider { private List<NoteEntity> noteEntities; public NoteItemProvider(List<NoteEntity> noteEntities) { this.noteEntities = noteEntities; } @Override public int getCount() { return noteEntities.size(); } @Override public Object getItem(int i) { return noteEntities.get(i); } @Override public long getItemId(int i) { return i; } @Override public Component getComponent(int i, Component component, ComponentContainer componentContainer) { if (component == null) component = LayoutScatter.getInstance( componentContainer.getContext()).parse( ResourceTable.Layout_note_item, null, false); ((Text)component.findComponentById(ResourceTable.Id_txtId)) .setText(noteEntities.get(i).getId().toString()); ((Text)component.findComponentById(ResourceTable.Id_txtTitle)) .setText(noteEntities.get(i).getTitle()); ((Text)component.findComponentById(ResourceTable.Id_txtContent)) .setText(noteEntities.get(i).getContent()); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(noteEntities.get(i).getDate()); ((Text)component.findComponentById(ResourceTable.Id_txtDate)) .setText(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(calendar.getTime())); return component; } }
为MainAbilitySlice类增加显示查询列表的功能,并在点击“+”按钮后跳转到详情页面:
public class MainAbilitySlice extends AbilitySlice { private NoteDao noteDao; private ListContainer listContainer; private Button button; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); noteDao = new NoteDaoImpl(this); listContainer = (ListContainer)findComponentById( ResourceTable.Id_lc); button = (Button)findComponentById(ResourceTable.Id_btn); button.setClickedListener(component -> { Intent intentNoteInfo = new Intent(); intentNoteInfo.setOperation(new Intent.OperationBuilder() .withDeviceId("") .withBundleName("com.hostest.orm") .withAbilityName("com.hostest.orm.NoteInfoAbility") .build()); startAbility(intentNoteInfo); }); } @Override public void onActive() { super.onActive(); listContainer.setItemProvider( new NoteItemProvider(noteDao.query())); } ... }
运行效果如下图所示:
点击查询列表中表项,跳转到详情页面,编辑被点击条目的内容:
public class MainAbilitySlice extends AbilitySlice { ... @Override public void onStart(Intent intent) { ... listContainer.setItemClickedListener(new ItemClickedListener() { @Override public void onItemClicked(ListContainer listContainer, Component component, int i, long l) { Intent intentNoteInfo = new Intent(); intentNoteInfo.setOperation(new Intent.OperationBuilder() .withDeviceId("") .withBundleName("com.hostest.orm") .withAbilityName("com.hostest.orm.NoteInfoAbility") .build()); intentNoteInfo.setParam("id", Integer.valueOf( ((Text)component.findComponentById( ResourceTable.Id_txtId)).getText()).intValue()); startAbility(intentNoteInfo); } }); ... } ... }
在详情页面中添加更新数据库的分支:
public class NoteInfoAbilitySlice extends AbilitySlice { ... @Override public void onStart(Intent intent) { ... int id = intent.getIntParam("id", -1); if (id != -1) { NoteEntity noteEntity = noteDao.query(id); tfTitle.setText(noteEntity.getTitle()); tfContent.setText(noteEntity.getContent()); } btnSave.setClickedListener(component -> { if (id != -1) { NoteEntity noteEntity = noteDao.query(id); noteEntity.setTitle(tfTitle.getText()); noteEntity.setContent(tfContent.getText()); noteEntity.setDate(System.currentTimeMillis()); if (noteDao.update(noteEntity)) new ToastDialog(this) .setText("保存成功") .setAlignment(LayoutAlignment.CENTER) .show(); else new ToastDialog(this) .setText("保存失败") .setAlignment(LayoutAlignment.CENTER) .show(); } else { NoteEntity noteEntity = new NoteEntity(); noteEntity.setTitle(tfTitle.getText()); noteEntity.setContent(tfContent.getText()); noteEntity.setDate(System.currentTimeMillis()); if (noteDao.insert(noteEntity)) new ToastDialog(this) .setText("保存成功") .setAlignment(LayoutAlignment.CENTER) .show(); else new ToastDialog(this) .setText("保存失败") .setAlignment(LayoutAlignment.CENTER) .show(); } }); } ... }
运行效果如下图所示:
为MainAbilitySlice类添加删除方法:
public class MainAbilitySlice extends AbilitySlice { ... @Override public void onActive() { super.onActive(); listContainer.setItemProvider( new NoteItemProvider(noteDao.query(), this)); } ... public void delete(int id) { if (noteDao.delete(id)) { new ToastDialog(this) .setText("删除成功") .setAlignment(LayoutAlignment.CENTER) .show(); listContainer.setItemProvider( new NoteItemProvider(noteDao.query(), this)); } else new ToastDialog(this) .setText("删除失败") .setAlignment(LayoutAlignment.CENTER) .show(); } }
在NoteItemProvider中添加对删除图像的点击处理:
public class NoteItemProvider extends BaseItemProvider { private List<NoteEntity> noteEntities; private MainAbilitySlice mainAbilitySlice; public NoteItemProvider(List<NoteEntity> noteEntities, MainAbilitySlice mainAbilitySlice) { this.noteEntities = noteEntities; this.mainAbilitySlice = mainAbilitySlice; } ... @Override public Component getComponent(int i, Component component, ComponentContainer componentContainer) { ... component.findComponentById(ResourceTable.Id_img) .setClickedListener(new ClickedListener() { @Override public void onClick(Component component) { new CommonDialog(componentContainer.getContext()) .setTitleText("提示") .setContentText("您真的要删除【" + noteEntities.get(i).getTitle() + "】吗?") .setButton(0, "确定", new IDialog.ClickedListener() { @Override public void onClick(IDialog iDialog, int j) { iDialog.destroy(); mainAbilitySlice.delete( noteEntities.get(i).getId()); } }) .setButton(1, "取消", new IDialog.ClickedListener() { @Override public void onClick(IDialog iDialog, int j) { iDialog.destroy(); } }) .setSize(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT) .show(); } }); return component; } }
运行效果如下图所示:
登录
https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/
添加项目和应用,通过自动签名部署到真机,运行调试。