表和数据库属性
创建你的数据库
在DBFlow中,创建数据库是非常简单的,只需要定义一个@Database
类:
@Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
public class AppDatabase {
public static final String NAME = "AppDatabase";
public static final int VERSION = 1;
}
P.S.你可以定义多个@Database
,但请保证他们没有重名。
预包装的数据库
如果你需要在创建时载入一个预包装好的数据库,只需要将数据库文件.db
放在src/main/assets/{databaseName}.db
,这样在DBFlow创建数据库的时候就会自动将这个数据库拷贝进来使用。但请注意,由于预包装的数据库文件已经被打包进了APK文件,所以我们无法在拷贝后将其删除,这会增加APK的大小(等于预包装数据库文件的大小)。
配置属性
全局冲突处理:通过定义insertConflict()
和updateConflict()
,任何没有被明确定义的@Table
都将使用与之对应的@Database
中的表。
(Global Conflict Handling: By specifying insertConflict()
and updateConflict()
here, any @Table
that does not explicitly define either itself will use the corresponding one from the associated @Database
.)
Kotlin:3.0开始,我们提供了对Kotlin的良好支持。
以前我们需要定义一个generatedClassSeparator()
为之工作:
@Database(generatedClassSeparator = "_")
数据库完整性检查:如果设置了consistencyChecksEnabled()
方法,我们将会在数据库打开时运行PRAGMA quick_check(1)
进行检查。如果检查失败,我们将尝试拷贝预定义的数据库文件覆盖当前数据库。
简单的数据库备份: backupEnabled()
开启数据库备份后,我们便可以简单的备份数据库了:
FlowManager.getDatabaseForTable(table).backupDB()
NOTE:请注意,这会首先生成一个临时的数据库,以防止备份失败。
开启外键常量(Constrants):使用foreignKeysSupported()=true
开启强制外键(the database enforce foreign keys)。如果设为false,我们仍然能够定义@ForeignKey
,但它们的关系将不是强制的。
自定义OpenHelper类:通过继承FlowSQLiteOpenHelper
我们可以定义自己的Helper类。注意,在自定义Helper类中需要实现FlowSQLiteOpenHelper
的构造函数:
public FlowSQLiteOpenHelper(BaseDatabaseDefinition flowManager, DatabaseHelperListener listener)
自定义的Helper类需要在@Database
注解中通过sqlHelperClass()
参数声明使用。
Model & Creation
所有的标准Table类都必须带上@Table
注解并实现Model
接口。为了方便,我们提供了Model
接口的标准实现BaseModel
。
Table数据类中支持的数据类型:
- 所有Java标准的数据类型(
boolean
、byte
、short
、int
、long
、float
、double
等)及相应的包装类,以及String
,当然我们还默认提供了对java.util.Date
、java.sql.Date
与Calendar
的支持。 - 其他不被支持的类型可以通过自定义
TypeConverter
来提供支持。范型类型的对象不被支持,容器类型如List、Map等同样也是不推荐的。如果你一定要使用容器,你也只能在无法获得范型参数情况下使用。 - 支持复合主键。
- 通过
@ForeignKey
可以嵌套其他的Model
,即一对一的关系。 - 任何被作为
@ForeignKey
使用的Model
都必须是ModelContainer
。 - 支持多个
@ForeignKey
- 通过在列属性中显式声明
@Column(typeConverter = SomeTypeConverter.class)
来提供自定义的TypeConverter
。
表Model的规则:
- 所有的
Model
都必须有一个公共无参构造。在查询时我们将会使用到这个构造函数。 - 对于一个继承自另一个
Model
的子类,library将会收集全部被@Column
注解标记的属性(包括父类中的)。 - 默认情况下为了方便,我们使用属性变量名作为数据表的列名,当然你也可以通过
@Column
中的参数来自定义列名。 - 为了使
_Adapter
类可以访问,属性必须是public
或者包私有的。
NOTE:Package private fields need not be in the same package as DBFlow will generate the necessary access methods to get to them. - 属性如果被定义为
private
,就必须提供对应的getter和setter方法,命名规则为:对属性{name}
,必须有get{Name}()
和set{Name}(columnType)
方法。 - 所有的Model类都必须是可访问的。内部类在3.0.0-beta1+后被支持。
Model示例
这里是一个Model
类的示例,其中包含一个主键(Table中必须有至少一个主键)和一个其他属性。
@Table(database = AppDatabase.class)
public class TestModel extends BaseModel {
// All tables must have a least one primary key
@PrimaryKey
String name;
// By default the column name is the field name
@Column
int randomNumber;
}
高级Table特性
为特定列指定自定义类型转换器
从3.0版本开始,你可以为特定列指定自定义的类型转换器TypeConverter
:
@Column(typeConverter = SomeTypeConverter.class)
SomeObject someObject;
这个自定义转换器将会覆盖默认的转换器和访问方法(除了私有属性,对于私有属性,自定义转换器将会拦截访问器方法)。
设置所有属性都作为列
我们可以通过设置@Table(allFields = true)
将所有类中的属性都设置为列。当打开这个设置后,DBFlow会将所有public/package private、non-final、non-static属性都作为@Column
。当然,这时你仍然需要显式地设置至少一个@PrimaryKey
主键。
私有属性列
正如上面所说,你需要将作为@Column
的属性都设为public
或package private,而如果一定要使用私有属性则需要提供相应的getter与setter方法:
@Table(database = TestDatabase.class)
public class PrivateModelTest extends BaseModel {
@PrimaryKey
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
访问器方法的命名方式按照java标准的命名方式,所以boolean
类型可以使用“is”:
@Table(database = TestDatabase.class, useIsForPrivateBooleans = true)
public class PrivateModelTest extends BaseModel {
@PrimaryKey
private String name;
@Column
private boolean selected;
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
//... etc
}
UNIQUE 约束
在SQLite中我们可以定义UNIQUE约束,即对于列或者列集合其在这个表中一定是唯一的。
UNIQUE('name', 'number') ON CONFLICT FAIL, UNIQUE('name', 'address') ON CONFLICT ROLLBACK
与SQL语句相似,DBFlow中我们是这样定义UNIQUE约束的:
@Table(database = AppDatabase.class,
uniqueColumnGroups = {@UniqueGroup(groupNumber = 1, uniqueConflict = ConflictAction.FAIL),
@UniqueGroup(groupNumber = 2, uniqueConflict = ConflictAction.ROLLBACK))
public class UniqueModel extends BaseModel {
@PrimaryKey
@Unique(unique = false, uniqueGroups = {1,2})
String name;
@Column
@Unique(unique = false, uniqueGroups = 1)
String number;
@Column
@Unique(unique = false, uniqueGroups = 2)
String address;
}