表和数据库属性

创建你的数据库

在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数据类中支持的数据类型

  1. 所有Java标准的数据类型(booleanbyteshortintlongfloatdouble等)及相应的包装类,以及String,当然我们还默认提供了对java.util.Datejava.sql.DateCalendar的支持。
  2. 其他不被支持的类型可以通过自定义TypeConverter来提供支持。范型类型的对象不被支持,容器类型如List、Map等同样也是不推荐的。如果你一定要使用容器,你也只能在无法获得范型参数情况下使用。
  3. 支持复合主键。
  4. 通过@ForeignKey可以嵌套其他的Model,即一对一的关系。
  5. 任何被作为@ForeignKey使用的Model都必须是ModelContainer
  6. 支持多个@ForeignKey
  7. 通过在列属性中显式声明@Column(typeConverter = SomeTypeConverter.class)来提供自定义的TypeConverter

表Model的规则

  1. 所有的Model必须有一个公共无参构造。在查询时我们将会使用到这个构造函数。
  2. 对于一个继承自另一个Model的子类,library将会收集全部被@Column注解标记的属性(包括父类中的)。
  3. 默认情况下为了方便,我们使用属性变量名作为数据表的列名,当然你也可以通过@Column中的参数来自定义列名。
  4. 为了使_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.
  5. 属性如果被定义为private,就必须提供对应的getter和setter方法,命名规则为:对属性{name},必须有get{Name}()set{Name}(columnType)方法。
  6. 所有的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;

}