創建你的數據庫
在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;
}