在这一章节中,我们快速浏览一下如何创建一个简单的数据库、表和建立Model
之间的关系。
蚂蚁王国 :我们打算存储关于蚁群的数据。我们想要追踪和标记某个蚁群的所有蚂蚁和蚁后。
蚁群的关系是这样的:
蚁群(1:1) ——> 蚁后(1:多)——>蚂蚁
为了初始化DBFlow,建议将下面的代码放到Application
类里。
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
FlowManager.init(this);
}
}
不要担心,这只是一个初始化的操作。即使你在其他Context
(Activity…) 中初始化她,她也将只持有Application
的context。
最后,不要忘了把自己继承的Application
放到manifest
里
<application android:name="{packageName}.ExampleApplication" ...>
</application>
在DBFlow里,使用@Database
注解便会产生一个BaseDatabaseDefinition
的一个子类,只在这一个Object
里将连接所有的tables
、 ModelAdapter
、Views
、Queries
等等。
在这个例子里,我们需要定义我们存储我们蚂蚁群族的的数据库:
@Database(name = ColonyDatabase.NAME, version = ColonyDatabase.VERSION)
public class ColonyDatabase {
public static final String NAME = "Colonies";
public static final int VERSION = 1;
}
最好创建两个常量NAME
和VERSION
,以便我们后面定义DBFlow的其他组件时引用它们。
Note: 如果你想要使用 SQLCipher 请阅读 setup here
现在我们已经有了一个存储我们蚁群数据的数据库,我们还要明确我们的基础表如何存储,那么我们需要有一个能够体现基础数据的Model
。
我们将开始在蚁群里的探索咯!一个蚁群只可能有一个蚁后。我们使用对象关系映射来定义我们的数据对象。一个class
对应着一个表,我们可以标记class
的每一个字段代表我们数据表里的一列。在DBFlow,所有与数据库表进行关系映射的object
类,必须实现Model
类(原因大概是说基类里定义里一些操作数据的规则)。继承BaseModel
类就可以方便地建立一个标准的表啦。
正确地定义一个表的姿势:
1. 使用@Table
注解标记一个类。
2. 指出这个表所属的数据库。就像下面的ColonyDatabase
。
3. 至少定义一个主键。
4. 这个类和她所有的对应数据库列的字段必须是包级私有private
、public
或者private(对应要有getters和setters),以便DBFlow编译时生成这些类并使用它们。
我们可以把蚁后Queen
大概定义成这样:
@Table(database = ColonyDatabase.class)
public class Queen extends BaseModel {
@PrimaryKey(autoincrement = true)
long id;
@Column
String name;
}
那么我们有了蚁后的定义,现在我们需要为蚁后定义她的蚁群Colony
:
@ModelContainer // more on this later.
@Table(database = ColonyDatabase.class)
public class Colony extends BaseModel {
@PrimaryKey(autoincrement = true)
long id;
@Column
String name;
}
现在我们有了一蚁后和蚁群表,我们要建立一个1:1映射的关系。我们想要这个数据库关注数据的删除,例如一个火灾发生了,烧掉了这个蚁群 Colony
。当Colony
被销毁了,我们认为蚁后也不存在了;如果我们”杀死“了这个蚁后那么她的蚁群也不再有了。
为了建立这个关系,我们将定义这个节点的外键。蚁后Queen
:
@ModelContainer
@Table(database = ColonyDatabase.class)
public class Queen extends BaseModel {
//...previous code here
@Column
@ForeignKey(saveForeignKeyModel = false)
Colony colony;
}
使用Model
作为外键,这样当从数据库里查询某列的某个值时,将可以自动加载这个关系。出于性能的考虑,我们默认把 savaForeignkeyModel=false
,这样当保存 Queen
对象时,将不会保存Colony
. 如果你想保持这对值的变化影响,记得设置saveForeignkeyModel =true
.
note:
在3.0版本中,我们不在需要明确给每个引用列定义@ForeignkeyReference
,DBFlow将基于@PrimaryKey
标记的引用表的类自动添加他们到表的定义里。 他们将以{foreignKeyFieldName}_{referencedColumnName}
的格式出现。(写好之后要rebuild project一下)
现在我们有了一个蚁群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);
}
}
我们定义了type
字段,它可能是干活的蚂蚁、产卵的蚂蚁或者其他。也定义了isMale
字段表示是男的还是女的。
在这个例子里,因为可能有很多很多蚂蚁,所以我们使用了 ForeignkeyContainer
。出于性能的考虑,这样可以延迟加载与其关联的 Queen
,当我们调用toModel
对Queen进行数据库查询时才会执行加载。基于这个原因,为了给ForeignKeyContainer
设置合适的值,你应该凭借 FlowManager.getContainerAdapter(Queen.class).toForeignKeyContainer(queen)
。调用它生成的方法并转换它到ForeignnKeyContainer
里。
因为ModelContainer
默认是不会产生的,为了使用ForeignKeyContainer
我们必须添加注解到Queen
类。
最后,使用@ForeignKeyContainer
可以避免循环的引用。如果Queen
和Colony
都使用Model
进行里关联引用,那我们将内存泄漏了,因为他们都在尝试从数据库里加载对方。
接着,我们通过延迟加载这些蚂蚁的方式建立1:多的关系,因为我们有几千只,不,也可能是几百万只蚂蚁要储存。
@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.DELETE
和SAVE
来代替ALL
。如果Queen
的数据什么时光变化,你都不希望保存他们,那么你只要使用DELETE
and LOAD
来替换下。
NOTE:为啥翻译这个说明文呢?
1. 项目里打算使用DBFlow。
2. 做开发快两年了,也打算写博客总结一下,写试试是什么个套路。
3. Markdown语法不熟,练练手。
4. 温习一下英语啦。
明天接着搞喽!