开始

本章我们将学习如何建立一个数据库、表单和Model之间的联系。

蚂蚁女皇:我们的教程将以蚂蚁王国为例,我们将建立 蚂蚁领地Colony、蚂蚁女王Queen、蚂蚁Ant 之间的关系表。

它们的关系如下:

Colony (1..1) -> Queen (1...many)-> Ants

初始化DBFlow

初始化DBFlow的操作,包括打开数据库、进行数据迁移和创建的操作都需要在自定义的Application中:

public class ExampleApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        FlowManager.init(this);
    }

}

当然,自定义的Application需要在AndroidManifest.xml文件中声明:

<application
  android:name="{packageName}.ExampleApplication"
  ...>
</application>

创建我们的数据库

在DBFlow中,通过Table类中声明对数据库类的连接来产生交互,并生成相应的代码。(In DBFlow, databases are placeholder objects that generate interactions from which tables "connect" themselves to.)

我们需要定义一个蚂蚁领地Colony的数据库来保存我们的小蚂蚁们:

@Database(name = ColonyDatabase.NAME, version = ColonyDatabase.VERSION)
public class ColonyDatabase {

  public static final String NAME = "Colonies";

  public static final int VERSION = 1;
}

作为一种推荐的写法,我们定义了NAMEVERSION两个公共常量,以方便我们定义的其他DBFlow组件能够在之后引用到这两个属性(如果需要的话)。

Note: 如果你希望使用 SQLCipher 对数据库进行加密的话,可以阅读 数据库加密 章节。

创建表并建立关系

现在我们有了一个地方可以创建我们的蚂蚁领地Colony了,但还需要建立Model来表示我们希望底层数据被如何保存。

蚂蚁女王的表(Table)

现在我们将会从上至下地建立我们的蚂蚁领地Colony,目前我们每个领地里只有一个女王。我们将会通过ORM(object-relational mapping)的方式建立数据库,这意味着这些Model中的每一项属性都将被映射为数据表中的一列。

在DBFlow中,每个与数据库连接的ORM对象类都必须继承Model接口。这是为了确保这些对象都能有相同的一些方法。通常为了方便我们继承BaseModel类,这个类也是Model的标准实现。

一个正确的数据表类需要以下几项:

  1. 对类添加@Table注解
  2. 声明所连接的数据库类,这里是ColonyDatabase
  3. 定义至少一个主键。
  4. 这个类和这个类中数据库相关列的修饰符必须是包内私有或者public
  5. 这样生成的_Adapter类能够访问到它。

NOTE: 列(Column)属性可以是private,但这样就必须指定公有public的getter和setter方法。

@Table(database = ColonyDatabase.class)
public class Queen extends BaseModel {

  @PrimaryKey(autoincrement = true)
  long id;

  @Column
  String name;

}

现在我们有了一个蚂蚁女王Queen,还需要为我们的女王建立一个领地Colony

蚂蚁领地的表(Table)

@ModelContainer
@Table(database = ColonyDatabase.class)
public class Colony extends BaseModel {

  @PrimaryKey(autoincrement = true)
  long id;

  @Column
  String name;

}

我们有了一个女王Queen和一个领地Colony,我们希望给他们建立一个一对一的关系。 我们希望当一个数据被移除,比如如果有一场大火烧毁了一个蚂蚁领地Colony,那么这个领地的女王Queen也活不长了,所以我们希望能“杀掉”与这个领地Colony相关联的女王Queen的数据。

1-1关系

为了建立关系,我们将会定义一个外键:

@ModelContainer
@Table(database = ColonyDatabase.class)
public class Queen extends BaseModel {

  //...previous code here

  @Column
  @ForeignKey(saveForeignKeyModel = false)
  Colony colony;

}

定义了外键的Model将会在载入数据库时通过查询自动将外键引用的值保存在这里。对于性能有要求的话可显式设置saveForeignKeyModel=false使Queen对象保存时不会保存对应的Colony对象。

在3.0版本中,我们不再需要显式设置@ForeignKeyReference来规定列属性了,DBFlow会自动分析和生成。

对于被用于ForeignKeyContainer属性的Model类,@ModelContainer注解是必须的。因为ForeignKeyContainer的实现需要生成一些必须的额外代码。

蚂蚁表(Table)与一对多关系

我们有了领地Colony和女王Queen,现在我们可以添加一些蚂蚁进去了:

@Table(database = ColonyDatabase.class)
public class Ant extends BaseModel {

  @PrimaryKey(autoincrement = true)
  long id;

  @Column
  String type;

  @Column
  boolean isMale;

  @ForeignKey(saveForeignKeyModel = false)
  ForeignKeyContainer<Queen> queenForeignKeyContainer;

  /**
  * Example of setting the model for the queen.
  */
  public void associateQueen(Queen queen) {
    queenForeignKeyContainer = FlowManager.getContainerAdapter(Queen.class).toForeignKeyContainer(queen);
  }
}

里面有typeisMale属性,用于表示这只蚂蚁的基本信息,比如是“工蚁”或者“其他”,是“公”还是“母”。

对于我们的几千只蚂蚁,我们使用了ForeignKeyContainer来保存外键。这是一种为性能优化的懒加载(lazy-load),只有在调用ForeignKeyContainertoModel()方法时才会对数据库执行实际的查询。

为了使用ForeignKeyContainer,我们需要给Queen添加@ModelContainer注解以生成相应的额外代码。

接下来我们可以通过懒加载添加一对多的关系了:

@ModelContainer
@Table(database = ColonyDatabase.class)
public class Queen extends BaseModel {
  //...

  // needs to be accessible for DELETE
  List<Ant> ants;

  @OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, variableName = "ants")
  public List<Ant> getMyAnts() {
    if (ants == null || ants.isEmpty()) {
            ants = SQLite.select()
                    .from(Ant.class)
                    .where(Ant_Table.queenForeignKeyContainer_id.eq(id))
                    .queryList();
    }
    return ants;
  }
}

如果你希望由你来进行关系的懒加载,只需要将OneToMany.Method.DELETESAVE 替换为 ALL

如果你希望无论Queen的数据如何变化它们都不会保存,只需要设置DELETELOAD