51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 2160|回复: 0
打印 上一主题 下一主题

Android技术前沿:DBFlow的实践

[复制链接]
  • TA的每日心情
    无聊
    2024-3-7 09:16
  • 签到天数: 43 天

    连续签到: 2 天

    [LV.5]测试团长

    跳转到指定楼层
    1#
    发表于 2018-3-27 14:00:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    DBFlow是一个基于AnnotationProcessing(注解处理器)的强大、健壮同时又简单的ORM框架。相比于使用模板
    代码生成的GreenDao,DBFlow使用更加方便;相比使用反射的ActiveAndroid,在性能有着绝对的优势。
    此框架设计为了速度、性能和可用性。消除了大量死板的数据库代码,取而代之的是强大而又简洁的API接口。

    相关链接:https://github.com/Raizlabs/DBFlow
    官方文档:https://agrosner.gitbooks.io/dbflow/content/

    数据持久化主要解决三个问题:

    数据库、表的创建
    表数据的增删改查操作
    数据库的版本管理:版本升级、数据迁移等
    本文档将按照这三个问题论述DBFlow的使用

    数据库、表的创建

    创建Java类指定数据库的名称和版本号。
    在Application的OnCreate方法中执行DBFlow SDK方法FlowManager.init(context); SDK会自动创建数据库。

    我这里写了一个示例,仅供参考:

    1. @Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
    2. public final class AppDatabase {
    3.     private AppDatabase() {
    4.     }

    5.     public static final String NAME = "studio"; // 数据库名称

    6.     public static final int VERSION = 2; // 数据库版本号

    7.     public static void setup(Context context) {
    8.         FlowManager.init(context);
    9.     }
    复制代码

        /**
         * 数据库的修改:
         * 1、PatientSession 表结构的变化
         * 2、增加表字段,考虑到版本兼容性,老版本不建议删除字段
         *

    1.   */
    2.     @Migration(version = 2, database = AppDatabase.class)
    3.     public static class Migration2PS extends AlterTableMigration<PatientSession> {

    4.         public Migration2PS(Class<PatientSession> table) {
    5.             super(table);
    6.         }

    7.         @Override
    8.         public void onPreMigrate() {
    9.             addColumn(SQLiteType.TEXT, "patientId");
    10.             addColumn(SQLiteType.TEXT, "pinyin");
    11.             addColumn(SQLiteType.TEXT, "sortLetters");
    12.             addColumn(SQLiteType.INTEGER, "attention");
    13.         }
    14.     }
    15. }

    16. public class MyApplication extends Application {

    17.     @Override
    18.     public void onCreate() {
    19.         super.onCreate();
    20.         AppDatabase.setup(this);
    21.     }
    22. }

    23. 表的创建也是通过Java类和Annotation来实现,示例如下:

    24. @Table(database = AppDatabase.class)
    25. public class PatientSession extends BaseModel implements Parcelable {
    26.     @PrimaryKey
    27.     @Column
    28.     public String patientDocId; // 患者档案ID
    29.     @PrimaryKey
    30.     @Column
    31.     public String docId;
    32.     @Column
    33.     public String patientDocName; // 患者档案姓名
    34.     @Column
    35.     public String patientName; // 患者账号微信昵称
    36.     @Column
    37.     public String patientId; // 患者账号微信ID
    38.     @Column
    39.     @SerializedName("note")
    40.     public String noteName; // 备注姓名
    41.     @Column
    42.     public String pinyin;
    43.     @Column
    44.     public String sortLetters;
    45.     ...
    46. }
    复制代码

    所有表对象集成BaseModel,该方法实现了该表对应的增删改查操作,数据库表的操作就直接转换成对Java
    表对象的操作了,简介明了。关于使用到的基本Annotation,@Table、@PrimaryKey、@Column、@Unique
    、@ForeignKey等,从名字就可以知晓这是表结构的基本术语。表会在使用的时候进行创建,而不是数据库
    创建的时候全部创建好。

    更多Annotation查阅:
    https://github.com/agrosner/DBFlowDocs/blob/master/Models.md

    表的增删改查、外键关联

    基本的增删改查操作通过BaseModel中的save()、delete()、insert()、update()方法来实现。

    手动查询操作:

    1. SQLite.select(EmployeeModel_Table.department,
    2. Method.avg(EmployeeModel_Table.salary.as("average_salary")),
    3.                 EmployeeModel_Table.title)
    4.       .from(EmployeeModel.class)
    5.       .groupBy(EmployeeModel_Table.department, EmployeeModel_Table.title);


    6. SQLite.select().from(UserProfile.class).where(UserProfile_Table.id.eq(doctorId)).querySingle();

    7. 核心类即 SQLite

    8. 事务操作可以通过TransactionManager 提供的相关方法来实现。

    9. TransactionManager.getInstance().addTransaction(new BaseTransaction() {
    10.                 @Override
    11.                 public Object onExecute() {
    12.                     Logger.d("Save Sessions in a Transaction");
    13.                     for (PatientSession session : sessions) {
    14.                         session.save();
    15.                     }
    16.                     return null;
    17.                 }

    18.                 @Override
    19.                 public int compareTo(Object another) {
    20.                     return 0;
    21.                 }
    22.             });
    复制代码

    外键关联

    官方文档说明:
    https://github.com/agrosner/DBFl ... er/Relationships.md

    DBFlow提供了外键关联的操作,同大部分ORM框架提供的功能类似,外键关联可实现查询、插入、删除等
    关联操作。DbFlow当前支持one-one, @OneToMany 和 @ManyToMany三种,one-one好说,后面两个使
    用时有点坑,简要说明一下。

    假设Solution是方案,SolutionItem是方案下面的子项,Solution-SolutionItem构成one-to-many关系,它们
    的外键关系建立如下:

    1. Solution声明one-to-many 关系
    2. @ModelContainer
    3. @Table(database = AppDatabase.class)
    4. public class Solution extends BaseModel implements Parcelable {
    5.     @PrimaryKey
    6.     public String solutionCode; // 方案编号
    7.     public List<SolutionItem> solutionItems;

    8.     @OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE},
    9.             variableName = "solutionItems")
    10.     public List<SolutionItem> getSolutionItems() {
    11.         if (solutionItems == null) {
    12.             solutionItems = new Select()
    13.                     .from(SolutionItem.class)
    14.                     .where(SolutionItem_Table.solution_id.eq(solutionCode))
    15.                     .queryList();
    16.         }
    17.         return solutionItems;
    18.     }
    19. }

    20. 要点:@ModelContainer @OneToMany 并且指定methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, 或者指定OneToMany.Method.ALL, 该指定可以实现修改的同步。

    21. SolutionItem指定外键
    22. @Table(database = AppDatabase.class)
    23. public class SolutionItem extends BaseModel implements Parcelable, Cloneable {
    24.     @PrimaryKey
    25.     public Integer itemId;
    26.     @Column
    27.     public String itemName;

    28.     @ForeignKey(references = {@ForeignKeyReference(columnName = SOLUTION_ID,
    29.             columnType = String.class, foreignKeyColumnName = "solutionCode")},
    30.             saveForeignKeyModel = false)
    31.     ForeignKeyContainer<Solution> solutionModelContainer;

    32.     public void associateSolution(Solution solution) {
    33.         solutionModelContainer = new ForeignKeyContainer<>(Solution.class);
    34.         solutionModelContainer.setModel(solution);
    35.         // put foreignKey
    36.         solutionModelContainer.put("solutionCode", solution.solutionCode);
    37.     }
    38. }

    39. 要点:
    40. 外键声明:@ForeignKey
    41. 外键关联: void associateSolution(Solution solution);

    42. 使用方式,通过调用associateSolution方法建立关联关系,然后再做DB操作,我写了一个测试类,代码如下:
    43. public class SolutionTest {

    44.     @org.junit.Before
    45.     public void setUp() throws Exception {
    46.         Solution solution = new Solution();
    47.         solution.solutionCode = "a";
    48.         List<SolutionItem> solutionItems = new ArrayList<>();
    49.         SolutionItem item1 = new SolutionItem(1, "麻黄");
    50.         SolutionItem item2 = new SolutionItem(2, "三七");
    51.         solutionItems.add(item1);
    52.         solutionItems.add(item2);
    53.         item1.associateSolution(solution);
    54.         item2.associateSolution(solution);
    55.         solution.solutionItems = solutionItems;
    56.         solution.save();
    57.     }

    58.     @org.junit.After
    59.     public void tearDown() throws Exception {

    60.     }

    61.     @Test
    62.     public void testOneToMany() throws Exception {
    63.         List<SolutionItem> items = SQLite.select().from(SolutionItem.class).queryList();
    64.         Assert.assertEquals("one-to-many save success", 2, items.size());

    65.         Solution solution = SQLite.select().from(Solution.class).where(Solution_Table.solutionCode.eq("a")).querySingle();
    66.         Assert.assertEquals("one-to-many get success", 2, solution.getSolutionItems().size());

    67.         solution.delete();

    68.         List<SolutionItem> items2 = SQLite.select().from(SolutionItem.class).queryList();
    69.         Assert.assertEquals("one-to-many delete success", 0, items2.size());
    70.     }
    71. }
    复制代码


    数据库的版本管理:版本升级、数据迁移

    官方文档说明:
    https://github.com/agrosner/DBFlowDocs/blob/master/Migrations.md

    https://github.com/agrosner/DBFl ... /Migration3Guide.md

    DBFlow提供了三个Migration方法:

    AlterTableMigration
    IndexMigration/IndexPropertyMigration
    UpdateTableMigration
    在前面所述的数据库类定义中有一个TableMigration的示例,实现了表字段的增加,只要在在数据库类中声明
    Migration类,并override 上述三个Migration基类的方法,在重载方法中做数据库升级等操作。

    结语

    以上描述大都从实践的角度来说明,有兴趣的读者可以研读一下DBFlow的代码,特别的,现在Annotation的
    使用是一个非常好的编码方式,可以学习之。另外需要说明的是,以上的实践也是我基于DBFlow官方文档进
    行的,读者在实践的时候也要结合官方文档,以免信息传递中出现信息差。

    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-5-3 07:43 , Processed in 0.063618 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表