├── usage
├── TableList.md
├── ModelContainers.md
├── ObservableModels.md
├── TriggersIndexesAndMore.md
├── ContentProviderGenerators.md
├── QueryModels.md
├── DatabaseModules.md
├── TypeConverters.md
├── Migrations.md
├── Conditions.md
├── Transactions.md
├── DBStructure.md
├── ModelCaching.md
├── GettingStarted.md
└── SQLQuery.md
├── demos
└── DBFlowDemo
│ ├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── values-v21
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── values-w820dp
│ │ │ │ │ └── dimens.xml
│ │ │ │ ├── menu
│ │ │ │ │ └── menu_main.xml
│ │ │ │ └── layout
│ │ │ │ │ ├── content_main.xml
│ │ │ │ │ ├── activity_main.xml
│ │ │ │ │ └── activity_getting_start.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── github
│ │ │ │ │ └── vankain
│ │ │ │ │ └── dbflowdemo
│ │ │ │ │ ├── db
│ │ │ │ │ ├── ColonyDatabase.java
│ │ │ │ │ └── models_gettingstart
│ │ │ │ │ │ ├── Colony.java
│ │ │ │ │ │ ├── Ant.java
│ │ │ │ │ │ └── Queen.java
│ │ │ │ │ ├── BaseApplication.java
│ │ │ │ │ └── ui
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── GettingStartActivity.java
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── vankain
│ │ │ │ └── dbflowdemo
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── github
│ │ │ └── vankain
│ │ │ └── dbflowdemo
│ │ │ └── ApplicationTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
│ ├── settings.gradle
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
├── Untitled Diagram.drawio
└── README.md
/usage/TableList.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/usage/ModelContainers.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/usage/ObservableModels.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/usage/TriggersIndexesAndMore.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/usage/ContentProviderGenerators.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VankaIn/DBFlow_CN/HEAD/demos/DBFlowDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VankaIn/DBFlow_CN/HEAD/demos/DBFlowDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VankaIn/DBFlow_CN/HEAD/demos/DBFlowDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VankaIn/DBFlow_CN/HEAD/demos/DBFlowDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VankaIn/DBFlow_CN/HEAD/demos/DBFlowDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DBFlowDemo
3 | Settings
4 | GettingStartActivity2
5 |
6 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/test/java/com/github/vankain/dbflowdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/db/ColonyDatabase.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo.db;
2 |
3 | import com.raizlabs.android.dbflow.annotation.Database;
4 |
5 | /**
6 | * Created by Administrator on 2016/3/4.
7 | */
8 | @Database(name = ColonyDatabase.NAME, version = ColonyDatabase.VERSION)
9 | public class ColonyDatabase {
10 |
11 | public static final String NAME = "Colonies";
12 |
13 | public static final int VERSION = 1;
14 | }
15 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/androidTest/java/com/github/vankain/dbflowdemo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/BaseApplication.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.stetho.Stetho;
6 | import com.raizlabs.android.dbflow.config.FlowManager;
7 |
8 | /**
9 | * Created by Administrator on 2016/3/4.
10 | */
11 | public class BaseApplication extends Application {
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | FlowManager.init(this);
16 | Stetho.initializeWithDefaults(this);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/usage/QueryModels.md:
--------------------------------------------------------------------------------
1 | # 查询模型
2 |
3 | Query Models 或`@QueryModel`是简单用于映射一个指定的,非标准查询的对象,返回一些不属于 `@Table`的列。类似 `@ModelView` 的定义,这些不能包含`@PrimaryKey`,但_必须_还扩展BaseQueryModel。
4 |
5 | 要创建一个:
6 |
7 | ```java
8 |
9 | @QueryModel(database = TestDatabase.class)
10 | public class TestQueryModel extends BaseQueryModel {
11 |
12 | @Column
13 | String newName;
14 |
15 | @Column
16 | long average_salary;
17 |
18 | @Column
19 | String department;
20 | }
21 |
22 | ```
23 |
24 | 规则同样适用于表和视图,该字段必须是包私有,公共或私人用,带有getter和setter方法。如果你想不冗长定义与或注释的所有字段,那就设置`@QueryModel(allFields = TRUE)` 。
25 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.0.0-beta6'
9 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | maven { url "https://jitpack.io" }
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/db/models_gettingstart/Colony.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo.db.models_gettingstart;
2 |
3 | import com.github.vankain.dbflowdemo.db.ColonyDatabase;
4 | import com.raizlabs.android.dbflow.annotation.Column;
5 | import com.raizlabs.android.dbflow.annotation.PrimaryKey;
6 | import com.raizlabs.android.dbflow.annotation.Table;
7 | import com.raizlabs.android.dbflow.structure.BaseModel;
8 |
9 | /**
10 | * Created by Administrator on 2016/3/4.
11 | */
12 | @Table(database = ColonyDatabase.class)
13 | public class Colony extends BaseModel {
14 |
15 | @PrimaryKey(autoincrement = true)
16 | public long id;
17 |
18 | @Column
19 | public String name;
20 |
21 | @Override
22 | public String toString() {
23 | return "id:"
24 | + id
25 | + "\nname:"
26 | + name;
27 | }
28 | }
--------------------------------------------------------------------------------
/demos/DBFlowDemo/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.neenbedankt.android-apt'
3 |
4 | android {
5 | compileSdkVersion 23
6 | buildToolsVersion "23.0.2"
7 |
8 | defaultConfig {
9 | applicationId "com.github.vankain.dbflowdemo"
10 | minSdkVersion 14
11 | targetSdkVersion 23
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | def dbflow_version = "3.0.0-beta3"
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | testCompile 'junit:junit:4.12'
27 | compile 'com.android.support:appcompat-v7:23.1.1'
28 | compile 'com.android.support:design:23.1.1'
29 | compile 'com.jakewharton:butterknife:7.0.1'
30 | compile 'com.facebook.stetho:stetho:1.3.1'
31 |
32 | apt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}"
33 | compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}"
34 | compile "com.github.Raizlabs.DBFlow:dbflow:${dbflow_version}"
35 | // sql-cipher database encyrption (optional)
36 | compile "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${dbflow_version}"
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/usage/DatabaseModules.md:
--------------------------------------------------------------------------------
1 | # Database Modules
2 | # 数据库模块
3 | DBFlow它的底层将产生一个GeneratedDatabaseHolder类,它包含了所有的数据库,表,一切应用程序将需要与库交互时的引用。
4 |
5 | 然而,在有些情况下的应用程序有一个library或子项目也使用DBFlow来管理其数据库时候。这是一个重要的方案,因为它可以让你在用多个应用程序中重复使的数据库。此前,DBFlow不支持这种用例,并试图这样做的时候会失败。
6 |
7 | 为了解决这个问题,你必须确保数据库的module被加载。幸运的是,这是一个非常简单的过程。
8 |
9 | 将数据库添加到模块,首先更新你的 `build.gradle` 库的自定义一个 `apt`参数,这将放置 `GeneratedDatabaseHolder`类---好像定义一个不同的类(在相同的包中),因此这些类没有重复,在你加入"apply plugin: 'com.neenbedankt.android-apt'"之后,而不是在你差生依赖前增加这点:
10 |
11 | ```groovy
12 | apt {
13 | arguments {
14 | targetModuleName 'Test'
15 | }
16 | }
17 | ```
18 |
19 | for KAPT:
20 | ```groovy
21 |
22 | kapt {
23 | generateStubs = true
24 | arguments {
25 | arg("targetModuleName", "Test")
26 | }
27 | }
28 |
29 | ```
30 |
31 | 通过传递`targetModuleName`,再把它添加到`GeneratedDatabaseHolder`创建`TestGeneratedDatabaseHolder` 模块。
32 |
33 | 在你的库(和应用),你应该使用标准方法初始化DBFlow。
34 |
35 | ```java
36 | public class ExampleApplication extends Application {
37 | @Override
38 | public void onCreate() {
39 | super.onCreate();
40 | FlowManager.init(this);
41 | }
42 | }
43 | ```
44 |
45 | 最后,指示DBFlow加载包含数据库模块(您可能需要构建应用程序生成的类文件才能够引用它)。
46 |
47 | ```java
48 | FlowManager.initModule(TestGeneratedDatabaseHolder.class);
49 | ```
50 |
51 | 这个方法可以被调用多次,而不会对应用程序的状态产生任何影响, 因为它使已经加载的那些的映射
52 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/db/models_gettingstart/Ant.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo.db.models_gettingstart;
2 |
3 | import com.github.vankain.dbflowdemo.db.ColonyDatabase;
4 | import com.raizlabs.android.dbflow.annotation.Column;
5 | import com.raizlabs.android.dbflow.annotation.ForeignKey;
6 | import com.raizlabs.android.dbflow.annotation.PrimaryKey;
7 | import com.raizlabs.android.dbflow.annotation.Table;
8 | import com.raizlabs.android.dbflow.config.FlowManager;
9 | import com.raizlabs.android.dbflow.structure.BaseModel;
10 | import com.raizlabs.android.dbflow.structure.container.ForeignKeyContainer;
11 |
12 | /**
13 | * Created by Administrator on 2016/3/4.
14 | */
15 | @Table(database = ColonyDatabase.class)
16 | public class Ant extends BaseModel {
17 |
18 | @PrimaryKey(autoincrement = true)
19 | public long id;
20 |
21 | @Column
22 | public String type;
23 |
24 | @Column
25 | public boolean isMale;
26 |
27 | @ForeignKey(saveForeignKeyModel = false)
28 | public ForeignKeyContainer queenForeignKeyContainer;
29 |
30 | /**
31 | * Example of setting the model for the queen.
32 | */
33 | public void associateQueen(Queen queen) {
34 | queenForeignKeyContainer = FlowManager.getContainerAdapter(Queen.class).toForeignKeyContainer(queen);
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "id:" + id + ";";
40 | }
41 | }
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/res/layout/activity_getting_start.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
31 |
32 |
33 |
38 |
39 |
44 |
45 |
--------------------------------------------------------------------------------
/Untitled Diagram.drawio:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/db/models_gettingstart/Queen.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo.db.models_gettingstart;
2 |
3 | import com.github.vankain.dbflowdemo.db.ColonyDatabase;
4 | import com.raizlabs.android.dbflow.annotation.Column;
5 | import com.raizlabs.android.dbflow.annotation.ForeignKey;
6 | import com.raizlabs.android.dbflow.annotation.ModelContainer;
7 | import com.raizlabs.android.dbflow.annotation.OneToMany;
8 | import com.raizlabs.android.dbflow.annotation.PrimaryKey;
9 | import com.raizlabs.android.dbflow.annotation.Table;
10 | import com.raizlabs.android.dbflow.sql.language.SQLite;
11 | import com.raizlabs.android.dbflow.structure.BaseModel;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Created by Administrator on 2016/3/4.
17 | */
18 | @ModelContainer
19 | @Table(database = ColonyDatabase.class)
20 | public class Queen extends BaseModel {
21 | @PrimaryKey(autoincrement = true)
22 | public long id;
23 |
24 | @Column
25 | public String name;
26 |
27 | @Column
28 | @ForeignKey(saveForeignKeyModel = false)
29 | public Colony colony;
30 |
31 | // needs to be accessible for DELETE
32 | List ants;
33 |
34 | @OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, variableName = "ants")
35 | public List getMyAnts() {
36 | if (ants == null || ants.isEmpty()) {
37 | ants = SQLite.select()
38 | .from(Ant.class)
39 | .where(Ant_Table.queenForeignKeyContainer_id.eq(id))
40 | .queryList();
41 | }
42 | return ants;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return "queen.id:" + id +
48 | "\nqueen.name:" + name +
49 | "\nqueen.colony.id:" + colony.id +
50 | "\nqueen.colony.name:" + colony.name;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/usage/TypeConverters.md:
--------------------------------------------------------------------------------
1 | # 类型转换器
2 |
3 | 类型转换使`Model`内字段不一定是数据库类型的。它们把该字段的值转换成在数据库可以定义的类型。它们还定义了当一个模型被加载的方式,我们使用转换器重新创建字段。__注意__:`TypeConverter`只能转化成常规列,由于数据中的非确定性映射,`PrimaryKey` 或`ForeignKey`是不能转化的。
4 |
5 | 这些转换器在所有数据库共享。
6 |
7 | 如果我们指定model值作为`Model` 类的话,可能有一些字段非常意外的行为被定义为Column.FOREIGN_KEY
8 |
9 | 下面是实现LocationConverter,把位置转化成字符串:
10 |
11 | ```java
12 |
13 | // First type param is the type that goes into the database
14 | // Second type param is the type that the model contains for that field.
15 | @com.raizlabs.android.dbflow.annotation.TypeConverter
16 | public class LocationConverter extends TypeConverter {
17 |
18 | @Override
19 | public String getDBValue(Location model) {
20 | return model == null ? null : String.valueOf(model.getLatitude()) + "," + model.getLongitude();
21 | }
22 |
23 | @Override
24 | public Location getModelValue(String data) {
25 | String[] values = data.split(",");
26 | if(values.length < 2) {
27 | return null;
28 | } else {
29 | Location location = new Location("");
30 | location.setLatitude(Double.parseDouble(values[0]));
31 | location.setLongitude(Double.parseDouble(values[1]));
32 | return location;
33 | }
34 | }
35 | }
36 | ```
37 |
38 | 要使用`LocationConverter`,使用类型转换器,我们只需添加类作为我们的表中的字段:
39 |
40 | ```java
41 |
42 | @Table(...)
43 | public class SomeTable extends BaseModel {
44 |
45 |
46 | @Column
47 | Location location;
48 |
49 | }
50 | ```
51 |
52 | ## 列具体的类型转换器
53 | 作为3.0的TypeConverter可以在column-by-column基础上使用。
54 |
55 | ```java
56 |
57 | @Table(...)
58 | public class SomeTable extends BaseModel {
59 |
60 |
61 | @Column(typeConverter = SomeTypeConverter.class)
62 | Location location;
63 |
64 | }
65 | ```
66 |
67 | _注_: `enum` 类举希望从默认枚举转换(从枚举到字符串),你必须定义一个自定义类型转换为列。
68 |
--------------------------------------------------------------------------------
/usage/Migrations.md:
--------------------------------------------------------------------------------
1 | # DB迁移变得容易!
2 | 每当你修改数据库架构,你需要在对应的`@Database`类内部通过增加数据库版本。还需要添加一个迁移到配置或通过定义迁移 `/assets/migrations/{DatabaseName}/{versionName.sql}`。
3 |
4 | 在首次创建数据库,您可以使用版本0指定一个迁移运行时!
5 |
6 | **注意**:任何提供的子类,如`AlterTableMigration`,`UpdateTableMigration`和`IndexMigration`应该只覆盖`onPreMigrate()`和**调用super.onPreMigrate()**,所以它的正确实例化。
7 |
8 | 注意:所有`迁移`必须只有一个`public`默认构造函数。
9 |
10 | ## 迁移类
11 | 基类,`BaseMigration`是一个非常简单的类来执行迁移:
12 |
13 | ```java
14 |
15 | @Migration(version = 2, database = AppDatabase.class)
16 | public class Migration1 extends BaseMigration {
17 |
18 | @Override
19 | public void migrate(DatabaseWrapper database) {
20 | List list = SQLite.select()
21 | .from(SomeClass.class)
22 | .queryList(database); // must pass in wrapper in order to prevent recursive calls to DB.
23 | }
24 | }
25 | ```
26 |
27 | ## 添加列
28 | 此处是添加到数据库的列的一个例子:
29 |
30 | 假设我们有原来的示例类:
31 |
32 | ```java
33 |
34 | @Table
35 | public class TestModel extends BaseModel {
36 |
37 | @Column
38 | @PrimaryKey
39 | String name;
40 |
41 | @Column
42 | int randomNumber;
43 | }
44 | ```
45 |
46 | 现在,我们要**添加**一列到这个表。我们有两种方式:
47 | - 利用SQL语句
48 |
49 | `ALTER TABLE TestModel ADD COLUMN timestamp INTEGER;` in a {dbVersion.sql} file in the assets directory. If we need to add any other column, we have to add more lines.
50 |
51 | - 通过`Migration`:
52 |
53 | ```java
54 |
55 | @Migration(version = 2, database = AppDatabase.class)
56 | public class Migration1 extends AlterTableMigration {
57 |
58 | @Override
59 | public void onPreMigrate() {
60 | // Simple ALTER TABLE migration wraps the statements into a nice builder notation
61 | addColumn(Long.class, "timestamp");
62 | }
63 | }
64 | ```
65 |
66 | ## 更新列
67 |
68 | ```java
69 |
70 | @Migration(version = 2, database = AppDatabase.class)
71 | public class Migration1 extends UpdateTableMigration {
72 |
73 | @Override
74 | public void onPreMigrate() {
75 | // UPDATE TestModel SET deviceType = "phablet" WHERE screenSize > 5.7 AND screenSize < 7;
76 | set(TestModel_Table.deviceType.is("phablet"))
77 | .where(TestModel_Table.screenSize.greaterThan(5.7), TestModel_Table.screenSize.lessThan(7));
78 | }
79 | }
80 | ```
81 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo.ui;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.FloatingActionButton;
5 | import android.support.design.widget.Snackbar;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.Toolbar;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 |
12 | import com.github.vankain.dbflowdemo.R;
13 |
14 | import butterknife.ButterKnife;
15 | import butterknife.OnClick;
16 |
17 | public class MainActivity extends AppCompatActivity {
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main);
23 | ButterKnife.bind(this);
24 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
25 | setSupportActionBar(toolbar);
26 |
27 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
28 | fab.setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View view) {
31 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
32 | .setAction("Action", null).show();
33 | }
34 | });
35 | }
36 |
37 | @Override
38 | public boolean onCreateOptionsMenu(Menu menu) {
39 | // Inflate the menu; this adds items to the action bar if it is present.
40 | getMenuInflater().inflate(R.menu.menu_main, menu);
41 | return true;
42 | }
43 |
44 | @Override
45 | public boolean onOptionsItemSelected(MenuItem item) {
46 | // Handle action bar item clicks here. The action bar will
47 | // automatically handle clicks on the Home/Up button, so long
48 | // as you specify a parent activity in AndroidManifest.xml.
49 | int id = item.getItemId();
50 |
51 | //noinspection SimplifiableIfStatement
52 | if (id == R.id.action_settings) {
53 | return true;
54 | }
55 |
56 | return super.onOptionsItemSelected(item);
57 | }
58 |
59 | @OnClick(R.id.btn_getting_start)
60 | public void onClick(View view) {
61 | switch (view.getId()){
62 | case R.id.btn_getting_start:
63 | GettingStartActivity.launch(this);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DBFlow_CN
2 | 翻译[DBFlow](https://github.com/Raizlabs/DBFlow)文档
3 |
4 | 
5 |
6 | [](https://jitpack.io/#Raizlabs/DBFlow) [](http://androidweekly.net/issues/issue-129) [](https://android-arsenal.com/details/1/1134)
7 |
8 | DBFlow是一个功能强大,简单易用的ORM安卓数据库库,他使用了**注释处理**.
9 |
10 | 这个库速度快,性能高,而且非常易用。它不但消除了大部分繁琐的公式化的数据库操作代码,而且还提交了一套功能强大,简单易用的API。
11 |
12 | DBFlow使sql代码就跟流式调用一样简洁,因此您可以集中精力去编写优秀的应用。
13 |
14 | #为什么要使用DBFlow
15 | DBFlow目的是把其他ORM的数据库最好的优点集合在一起,而且将它们进一步优化。DBFlow不只是让你知道如何解决你的功能上的问题,而且它使你容易处理Android上的数据库。让我们好好利用DBFlow,使我们尽可能的把程序写的最好。
16 |
17 | - **可扩展性**:`Model` 是一个接口,无需子类,但为了方便起见,我们建议使用 `BaseModel`。你可以不继承任何`Model`类在不同的包中的类,并把它们作为你的数据库表。你也可以继承其他`Model`然后同时加入`@Column`,他们又可以在不同的packages中。此外,在该库的子类对象,能满足您的需求。(翻译不好)
18 | - **速度**:这个库内置Java的注释处理代码生成,有几乎为零的运行时性能(反射是主要的,生成的数据库模块的构造方法)。该库通过生成的代码,你可以节省样板代码和维护时间。凭借强大的模式高速缓存(多主键`Model` 也行),你可以通过重复使用,在这里可能超过SQLite的速度。我们支持延迟加载,如支持@ForeignKey或@OneToMany,使查询发生的速度超快。
19 | - **SQLite流式查询**:此库中的查询尽可能坚持SQLite的原生查询, `select(name, screenSize).from(Android.class).where(name.is("Nexus 5x")).and(version.is(6.0)).querySingle()`
20 | - **开源**:该库是完全开源,不仅欢迎贡献,而且鼓励。
21 | - **强大**: 我们支持触发器,模型视图,索引,迁移,在同一个线程中,内置的数据库请求队列执行操作,还有更多的功能。。。
22 | - **多个数据库,多个模块**:我们无缝支持多个数据库文件,数据库模块,在同一时间。
23 | - **基于SQLite**:SQLite是世界上最广泛使用的数据库引擎。。。。。
24 |
25 | # 使用文档
26 | 想了解更多详细的使用,看看这些部分:
27 |
28 | [入门](usage/GettingStarted.md)
29 |
30 | [表格和数据库属性](usage/DBStructure.md)
31 |
32 | [关于DBFlow的多个实例/多个数据库模块](usage/DatabaseModules.md)
33 |
34 | [使用包装类对sql语句声明](usage/SQLQuery.md)
35 |
36 | [属性和条件](usage/Conditions.md)
37 |
38 | [事物处理](usage/Transactions.md)
39 |
40 | [类型转换器](usage/TypeConverters.md)
41 |
42 | [强大的模型缓存](usage/ModelCaching.md)
43 |
44 | [多模型查询](usage/QueryModels.md)
45 |
46 | [Content Provider Generation](usage/ContentProviderGenerators.md)
47 |
48 | [数据库迁移](usage/Migrations.md)
49 |
50 | [模型容器](usage/ModelContainers.md)
51 |
52 | [观察模型](usage/ObservableModels.md)
53 |
54 | [查询列表](usage/TableList.md)
55 |
56 | [触发器,索引,以及更多](usage/TriggersIndexesAndMore.md)
57 |
58 | [SQLCipher支持]不翻译
59 |
60 | [Kotlin 扩展]不翻译
61 |
62 | # 导入到你的项目中
63 | 如果你使用KAPT (Kotlin's APT),跳过这第一步。
64 |
65 | 我们需要包括 [apt plugin](https://bitbucket.org/hvisser/android-apt)在我们的classpath中,使它来支持**注释处理**:
66 |
67 | ```groovy
68 |
69 | buildscript {
70 | repositories {
71 | jcenter()
72 | }
73 | dependencies {
74 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
75 | }
76 | }
77 |
78 | allProjects {
79 | repositories {
80 | // required to find the project's artifacts
81 | maven { url "https://jitpack.io" }
82 | }
83 | }
84 | ```
85 |
86 | 该库添加到项目级的build.gradle,使apt插件支持**注释处理**:
87 |
88 | ```groovy
89 |
90 | apply plugin: 'com.neenbedankt.android-apt'
91 |
92 | def dbflow_version = "3.0.0-beta4"
93 | // or dbflow_version = "develop-SNAPSHOT" for grabbing latest dependency in your project on the develop branch
94 | // or 10-digit short-hash of a specific commit. (Useful for bugs fixed in develop, but not in a release yet)
95 |
96 | dependencies {
97 | apt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}"
98 | // kapt for kotlin apt
99 | compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}"
100 | compile "com.github.Raizlabs.DBFlow:dbflow:${dbflow_version}"
101 |
102 | // sql-cipher database encyrption (optional)
103 | compile "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${dbflow_version}"
104 |
105 | // kotlin extensions
106 | compile "com.github.Raizlabs.DBFlow:dbflow-kotlinextensions:${dbflow_version}"
107 | }
108 |
109 | ```
110 |
111 |
112 | # Translate By
113 | [VankaIn](https://github.com/VankaIn) ([email](Vancouver031@gmail))
114 |
--------------------------------------------------------------------------------
/usage/Conditions.md:
--------------------------------------------------------------------------------
1 | #属性,条件和条件组
2 | DBFlow,通过Java注释处理,生成一个`_Table`表示你的 `Model`。生成的每个领域都是子类的`IProperty`。每个的`IProperty`代表在相应表中的列,并提供了一个类型安全的条件操作把它变成SQLCondition或变异成另一种属性。
3 |
4 | `SQLCondition`是一个代表SQL语句中的条件语句的接口。这是一个接口,这样其他类型的条件可以使用,并且允许最大的灵活性,以满足您的需求。
5 |
6 | 例如,写在原始的SQLite:
7 |
8 | ```sql
9 |
10 | `name` = 'Test'
11 |
12 | `name` = `SomeTable`.`Test`
13 |
14 | `name` LIKE '%Test%'
15 |
16 | `name` != 'Test'
17 |
18 | `salary` BETWEEN 15000 AND 40000
19 |
20 | `name` IN('Test','Test2','TestN')
21 |
22 | ((`name`='Test' AND `rank`=6) OR (`name`='Bob' AND `rank`=8))
23 | ```
24 |
25 | ## 如何使用条件
26 | 建议我们的查询从`Model`的`属性`中创造`条件`。
27 |
28 | 我们有一个简单的表:
29 |
30 | ```java
31 | @Table(database = TestDatabase.class)
32 | public class TestModel3 {
33 |
34 | @PrimaryKey
35 | String name;
36 |
37 | @Column
38 | String type;
39 | }
40 | ```
41 |
42 | 有了这个定义, DBFlow将帮我们生产一个TestModel3_Table类:
43 |
44 | ```java
45 |
46 | public final class TestModel3_Table {
47 | public static final PropertyConverter PROPERTY_CONVERTER = new PropertyConverter(){
48 | public IProperty fromName(String columnName) {
49 | return com.raizlabs.android.dbflow.test.sql.TestModel3_Table.getProperty(columnName);
50 | }
51 | };
52 |
53 | public static final Property type = new Property(TestModel3.class, "type");
54 |
55 | public static final Property name = new Property(TestModel3.class, "name");
56 |
57 | public static final IProperty[] getAllColumnProperties() {
58 | return new IProperty[]{type,name};
59 | }
60 |
61 | public static BaseProperty getProperty(String columnName) {
62 | columnName = QueryBuilder.quoteIfNeeded(columnName);
63 | switch (columnName) {
64 | case "`type`": {
65 | return type;
66 | }
67 | case "`name`": {
68 | return name;
69 | }
70 | default: {
71 | throw new IllegalArgumentException("Invalid column name passed. Ensure you are calling the correct table's column");
72 | }
73 | }
74 | }
75 | }
76 | ```
77 |
78 | 从生成的类文件中使用的字段,我们现在可以在我们的查询中使用`属性`生成`SQLCondition`:
79 |
80 | ```java
81 |
82 | TestModel3_Table.name.is("Test"); // `name` = 'Test'
83 | TestModel3_Table.name.withTable().is("Test"); // `TestModel3`.`name` = 'Test'
84 | TestModel3_Table.name.like("%Test%");
85 |
86 | // `name`=`AnotherTable`.`name`
87 | TestModel3_Table.name.eq(AnotherTable_Table.name);
88 | ```
89 |
90 | A whole set of `SQLCondition` operations are supported for `Property` generated for a Table including:
91 | 1. `is()`, `eq()` -> =
92 | 2. `isNot()`, `notEq()` -> !=
93 | 3. `isNull()` -> IS NULL / `isNotNull()`IS NOT NULL
94 | 4. `like()`, `glob()`
95 | 5. `greaterThan()`, `greaterThanOrEqual()`, `lessThan()`, `lessThanOrEqual()`
96 | 6. `between()` -> BETWEEN
97 | 7. `in()`, `notIn()`
98 |
99 | 此外,我们可以做加法和减法:
100 |
101 | ```java
102 |
103 | SomeTable_Table.latitude.plus(SomeTable_Table.longitude).lessThan(45.0); // `latitude` + `longitude` < 45.0
104 |
105 | SomeTable_Table.latitude.minus(SomeTable_Table.longitude).greaterThan(45.0); // `latitude` - `longitude` > 45.0
106 |
107 | ```
108 |
109 | ## 条件组
110 | 该`ConditionGroup`是`ConditionQueryBuilder`的继任者。这是有缺陷的,就是它符合的`QueryBuilder`,还包含 `Condition`,以及所需要的类型的参数都需要属于它自己的表。
111 |
112 | `ConditionGroup`是任意集合 `SQLCondition`,可以组合成一个单一的条件,SELECT projection,或者被用作`SQLCondition`在另一个`ConditionGroup`内。
113 |
114 | 这用于包装查询语句,支持其他各种查询和类。
115 |
116 | ```java
117 |
118 | SQLite.select()
119 | .from(MyTable.class)
120 | .where(MyTable_Table.someColumn.is("SomeValue"))
121 | .and(MyTable_Table.anotherColumn.is("ThisValue"));
122 |
123 | // SELECT * FROM `MyTable` WHERE `someColumn`='OneValue' OR (`someColumn`='SomeValue' AND `anotherColumn`='ThisValue')
124 | SQLite.select()
125 | .from(MyTable.class)
126 | .where(MyTable.someColumn.is("OneValue"))
127 | .or(ConditionGroup.clause()
128 | .and(MyTable_Table.someColumn.is("SomeValue")
129 | .AND(MyTable_Table.anotherColumn.is("ThisValue"));
130 |
131 |
132 | ```
133 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/app/src/main/java/com/github/vankain/dbflowdemo/ui/GettingStartActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.vankain.dbflowdemo.ui;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.Toast;
10 |
11 | import com.github.vankain.dbflowdemo.R;
12 | import com.github.vankain.dbflowdemo.db.models_gettingstart.Ant;
13 | import com.github.vankain.dbflowdemo.db.models_gettingstart.Colony;
14 | import com.github.vankain.dbflowdemo.db.models_gettingstart.Queen;
15 | import com.raizlabs.android.dbflow.sql.language.SQLite;
16 |
17 | import java.util.List;
18 |
19 | import butterknife.ButterKnife;
20 | import butterknife.OnClick;
21 |
22 | /**
23 | * Created by Administrator on 2016/3/4.
24 | */
25 | public class GettingStartActivity extends Activity {
26 | public static final String TAG = "GettingStartActivity";
27 | public static void launch(Context context) {
28 | Intent intent = new Intent(context, GettingStartActivity.class);
29 | context.startActivity(intent);
30 | }
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_getting_start);
36 | ButterKnife.bind(this);
37 | }
38 |
39 | @OnClick({R.id.btn_insert_colony, R.id.btn_read_add_delete_colony,
40 | R.id.btn_insert_queen, R.id.btn_read_queen, R.id.btn_insert_ants,
41 | R.id.btn_read_ants})
42 | public void onClickView(View view) {
43 | switch (view.getId()) {
44 | case R.id.btn_insert_colony:
45 | insertColony();
46 | break;
47 | case R.id.btn_read_add_delete_colony:
48 | readColony();
49 | break;
50 | case R.id.btn_insert_queen:
51 | insertQueen();
52 | break;
53 | case R.id.btn_read_queen:
54 | readQueen();
55 | break;
56 | case R.id.btn_insert_ants:
57 | addInsertAdds();
58 | break;
59 | case R.id.btn_read_ants:
60 | readAntsByQueen();
61 | break;
62 | }
63 | }
64 |
65 | private void insertColony() {
66 | Colony colony = new Colony();
67 | colony.name = "colony1";
68 | colony.insert();
69 | }
70 |
71 | private void readColony() {
72 | Colony colony = SQLite.select().from(Colony.class).querySingle();
73 | Toast.makeText(GettingStartActivity.this, "id:"
74 | + colony.id + "\nname:"
75 | + colony.name, Toast.LENGTH_LONG)
76 | .show();
77 | }
78 |
79 | private void insertQueen() {
80 | Colony colony = new Colony();
81 | colony.name = "queen's colony";
82 | colony.insert();
83 | Queen quean = new Queen();
84 | quean.name = "queen1";
85 | quean.colony = colony;
86 | quean.insert();
87 | }
88 |
89 | private void readQueen() {
90 | Queen queen = SQLite.select().from(Queen.class).querySingle();
91 | Toast.makeText(GettingStartActivity.this,
92 | queen.toString(),
93 | Toast.LENGTH_LONG).show();
94 | }
95 |
96 |
97 |
98 | private void addInsertAdds(){
99 | Toast.makeText(GettingStartActivity.this, "inserting", Toast.LENGTH_SHORT).show();
100 | long startTime = System.currentTimeMillis();
101 | Queen queen = SQLite.select().from(Queen.class).querySingle();
102 | for(int i=0; i<1000; i++){
103 | Ant ant = new Ant();
104 | ant.type = "other";
105 | ant.isMale = true;
106 | ant.associateQueen(queen);
107 | ant.insert();
108 | }
109 | long endTime = System.currentTimeMillis();
110 | Toast.makeText(GettingStartActivity.this, "insertsuccess", Toast.LENGTH_SHORT).show();
111 | Log.i("TAG", (endTime-startTime) + "");
112 | }
113 |
114 | private void readAntsByQueen(){
115 | long startTime = System.currentTimeMillis();
116 | Queen queen = SQLite.select().from(Queen.class).querySingle();
117 | List ants = queen.getMyAnts();
118 | long endTime = System.currentTimeMillis();
119 | Log.i("TAG", (endTime-startTime) + "");
120 | String s = "";
121 | for(int i=0; i(ProcessModelInfo.withModels(models)));
49 | ```
50 |
51 | ## 批量处理`Model`
52 | `ProcessModelInfo`:描述了如何用一个事务来保存信息,例如`DBTransactionInfo`,table,一组models,和一个TransactionListener为事务。**注意**:该类的建立是为了大幅度简化方法数的TransactionManager上。
53 |
54 | 对于跨上百个`Model`的大行动中,首选的方法是在`DBTransactionQueue`运行它。这将在同一线程上进行数据库操作,以减轻同步锁定和UI线程阻塞。
55 |
56 | 对于大规模的`save()`操作,首选的方法是通过 `DBBatchSaveQueue`。这将运行一个批处理`DBTransaction` 一旦队列满(默认为50 models,并且可以修改)在同一时间上的所有模型中。如果要保存少量的items,或者需要他们准确地保存,最好的选择是使用常规的保存事务。
57 |
58 |
59 | ### 例
60 |
61 | ```java
62 |
63 | ProcessModelInfo processModelInfo = ProcessModelInfo.withModels(models)
64 | .result(resultReceiver)
65 | .info(myInfo);
66 |
67 | TransactionManager.getInstance().saveOnSaveQueue(models);
68 |
69 | // or directly to the queue
70 | TransactionManager.getInstance().addTransaction(new SaveModelTransaction<>(processModelInfo));
71 |
72 | // Updating only updates on the ``DBTransactionQueue``
73 | TransactionManager.getInstance().addTransaction(new UpdateModelListTransaction(processModelInfo));
74 |
75 | TransactionManager.getInstance().addTransaction(new DeleteModelListTransaction(processModelInfo));
76 | ```
77 |
78 | 有很多各种各样的事务管理器方法在`DBTransactionQueue`中执行,用于用于读取,保存,updateing和删除。一探究竟!
79 |
80 | ## 检索模型
81 | 该`SelectListTransaction`和`SelectSingleModelTransaction`在`DBTransactionQueue`中进行select,它完成时`TransactionListener`将在UI线程调用。一个正常的SQLite.select()将当前线程上完成。虽然这是简单的数据库操作,这要好得多,在`DBTransactionQueue`执行这些操作使其他操作不会导致主线程的“锁”。
82 |
83 | ```java
84 |
85 | // Just get all items from the table
86 | // You can even use Select and Where statements instead
87 | TransactionManager.getInstance().addTransaction(new SelectListTransaction<>(new TransactionListenerAdapter() {
88 | @Override
89 | public void onResultReceived(List testModels) {
90 | // on the UI thread, do something here
91 | }
92 | }, TestModel.class, condition1, condition2,..);
93 | ```
94 |
95 | ## 自定义事务处理
96 | 这个库可以很容易添加自定义的事务。将它们添加到事务管理方式:
97 |
98 | ```java
99 |
100 | TransactionManager.getInstance().addTransaction(myTransaction);
101 | ```
102 |
103 |
104 | 有几个方法可以创建你一个你想要的特定事务:
105 | - 扩展 `BaseTransaction`将要求你在 `onExecute()`进行一些操作.
106 |
107 | ```java
108 |
109 | BaseTransaction testModel1BaseTransaction = new BaseTransaction() {
110 | @Override
111 | public TestModel1 onExecute() {
112 | // do something and return an object
113 | return testModel;
114 | }
115 | };
116 | ```
117 |
118 | - `BaseResultTransaction` 增加了一个简单的 `TransactionListener` ,确保您可以监听事务更新。
119 |
120 | ```java
121 |
122 | BaseResultTransaction baseResultTransaction = new BaseResultTransaction(dbTransactionInfo, transactionListener) {
123 | @Override
124 | public TestModel1 onExecute() {
125 | return testmodel;
126 | }
127 | };
128 | ```
129 |
130 | - `ProcessModelTransaction`发在在一个model内,使您能够定义如何在`DBTransactionQueue`处理在每一款model。
131 |
132 | ```java
133 |
134 | public class CustomProcessModelTransaction extends ProcessModelTransaction {
135 |
136 | public CustomProcessModelTransaction(ProcessModelInfo modelInfo) {
137 | super(modelInfo);
138 | }
139 |
140 | @Override
141 | public void processModel(ModelClass model) {
142 | // process model class here!
143 | }
144 | }
145 | ```
146 |
147 | - `QueryTransaction`有你使用一个可查询的检索游标无你用什么方式。
148 |
149 | ```java
150 |
151 | // any Where, From, Insert, Set, and StringQuery all are valid parameters
152 | TransactionManager.getInstance().addTransaction(new QueryTransaction(DBTransactionInfo.create(),
153 | SQLite.delete().from(MyTable.class).where(MyTable_Table.name.is("Deleters"))));
154 | ```
155 |
--------------------------------------------------------------------------------
/usage/DBStructure.md:
--------------------------------------------------------------------------------
1 | # 表格和数据库属性
2 | ## 创建数据库
3 | 用DBFlow创建数据库是超级简单的。只要简单地定义一个占位符 `@Database` 类:
4 |
5 | ```java
6 |
7 | @Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
8 | public class AppDatabase {
9 |
10 | public static final String NAME = "AppDatabase";
11 |
12 | public static final int VERSION = 1;
13 | }
14 | ```
15 |
16 | _P.S._ 你可以定义为许多`@Database` 只要你喜欢,但是名称要唯一的。
17 |
18 | ### 预包装数据库
19 | 如果想为你得app包含预先准备好的数据库,直接把 ".db" 文件复制到`src/main/assets/{databaseName}.db`目录中。在创建数据库时,我们复制该文件给应用使用。由于这是APK内预先包装,在复制完后,我们无法将其删除,导致APK变大(取决于数据库文件大小)。
20 |
21 |
22 | ### 配置属性
23 | **全局冲突处理**:在这里通过指定`insertConflict()`和 `updateConflict()`,任何 `@Table`没有明确定上面2个属性的任意一个,他将会使用最适合的一个关联`@Database`。
24 |
25 | 以前,你需要定义一个`generatedClassSeparator()` 才能运行。
26 |
27 | 如果要更改默认`_` ,只需添加一些字符串:
28 |
29 | ```java
30 |
31 | @Database(generatedClassSeparator = "$$")
32 | ```
33 |
34 | **开放数据库的完整性检查**:每当打开数据,`consistencyChecksEnabled()` 将运行一个`PRAGMA quick_check(1)`,如果失败,它将尝试复制预先打包的数据库。
35 |
36 | **轻松备份数据库**:`backupEnabled()` 调用,可以备份数据库
37 |
38 | ```
39 | FlowManager.getDatabaseForTable(table).backupDB()
40 | ```
41 |
42 | 请注意:当数据库备份失败时,这将创建一个临时的第三方数据库。
43 |
44 | **打开外键Constrants**:通过设置`foreignKeysSupported()=true` ,让数据库强制执行外键。默认情况下此处于关闭状态。们仍然可以定义@ForeignKey,但他们的关系不执行。
45 |
46 | **OpenHelper的定义实现**:他们必须为FlowSQLiteOpenHelper配置构造参数:
47 |
48 | ```java
49 | public FlowSQLiteOpenHelper(BaseDatabaseDefinition flowManager, DatabaseHelperListener listener)
50 | ```
51 |
52 | 要 `public`,并在 `@Database` 注解中指出了 `sqlHelperClass()` 自定义类。
53 |
54 | ## 模型与创造
55 | 所有标准表必须使用`@Table` 注解和实现`Model`接口。为方便起见,BaseModel提供了一个默认的实现。
56 |
57 | **`Model`的支持**:
58 | 1. Fields: 支持任何默认Java类型.
59 | 2. `类型转换器`: 您可以定义非标准类的列,如`Date`, `Calendar`等,这些可以在列逐列的基础上进行配置。
60 | 3. 复合 `@PrimaryKey`
61 | 4. 复合 `@ForeignKey`. 嵌套 `Model`, `ModelContainer`, `ForeignKeyContainer` or standard `@Column`.
62 | 5. 结合 `@PrimaryKey` 和 `@ForeignKey`, 以及那些可以有复杂的主键。
63 | 6. 内部类
64 |
65 | **Models的规则和技巧**:
66 | 1.`Model`必须有一个可访问的默认构造函数。这可以是public或package private.。
67 | 2. 子类是完全支持。DBFlow将收集并结合每个子类“的注释并将它们组合为当前类。
68 | 3. 字段可以是public,package private(我们生成package helpers访问),或private(要有getter和setter)。Private fields需要有一个getter `get{Name}`和setter `set{Name}`。这些也可以被配置。
69 | 4. 我们可以继承非`Model`的类,这样类可以通过扩展`inheritedColumns()` (或`inheritedPrimaryKeys()`)。这些都必须通过带有对应的getter和setter的 package-private, public, or private
70 | 5. 结合 `@PrimaryKey` 和 `@ForeignKey`, 以及那些可以有复杂的主键。
71 | 6. 要启用缓存,设置 `cachingEnabled = true`,这将加快在大多数情况下检索。
72 |
73 |
74 | ### 简单例子
75 | 这是一个带有一个主键(一个`Model`最少有一个)和其他列的 `Model`。
76 |
77 | ```java
78 | @Table(database = AppDatabase.class)
79 | public class TestModel extends BaseModel {
80 |
81 | // All tables must have a least one primary key
82 | @PrimaryKey
83 | String name;
84 |
85 | // By default the column name is the field name
86 | @Column
87 | int randomNumber;
88 |
89 | }
90 | ```
91 |
92 | ## 高级表功能
93 | ### 为特定的列自定义类型转换器
94 | 在3.0,现在您可以为特定`@Column`指定一个`TypeConverter`,为转换器指定对应的`Column` :
95 |
96 |
97 | ```java
98 |
99 | @Column(typeConverter = SomeTypeConverter.class)
100 | SomeObject someObject;
101 | ```
102 |
103 | 它将取代通常的转换/访问方法(除如果该字段是私有的,它保留了基于私有访问方法)。
104 |
105 | ### 所有字段作为列
106 | 因为其他库也这样做,你可以设置 `@Table(allFields = true)` 打开使用所有的public/package private,non-final,,以及non-static 字段作为 `@Column`。你仍然需要提供至少一个 `@PrimaryKey` 字段。
107 |
108 | 如果您需要忽略一个字段,使用 `@ColumnIgnore` 注释。
109 |
110 | ### 私人列
111 | 如果你想使用私有字段,只需指定一个getter和setter,格式:`name` -> `getName()` + `setName(columnFieldType)`
112 |
113 | ```java
114 |
115 | @Table(database = TestDatabase.class)
116 | public class PrivateModelTest extends BaseModel {
117 |
118 | @PrimaryKey
119 | private String name;
120 |
121 |
122 | public String getName() {
123 | return name;
124 | }
125 |
126 | public void setName(String name) {
127 | this.name = name;
128 | }
129 | }
130 | ```
131 |
132 | `boolean` fields can use "is"
133 |
134 | ```java
135 |
136 | @Table(database = TestDatabase.class, useIsForPrivateBooleans = true)
137 | public class PrivateModelTest extends BaseModel {
138 |
139 | @PrimaryKey
140 | private String name;
141 |
142 | @Column
143 | private boolean selected;
144 |
145 | public boolean isSelected() {
146 | return selected;
147 | }
148 |
149 | public void setSelected(boolean selected) {
150 | this.selected = selected;
151 | }
152 |
153 | //... etc
154 | }
155 | ```
156 |
157 | ### 默认值
158 | 当字段的值丢失或遗漏,希望提供在数据库中默认值。SQLite使用`DEFAULT`来实现。
159 |
160 |
161 | 然而,在DBFlow也不是那么容易,因为我们依靠预编译实现这个`INSERT`声明。因此,作为一种妥协,这些值插入这样:
162 |
163 |
164 | ```java
165 | @Table(database = TestDatabase.class)
166 | public class DefaultModel extends TestModel1 {
167 |
168 | @Column(defaultValue = "55")
169 | Integer count;
170 |
171 | }
172 | ```
173 |
174 | In the `_Adapter`:
175 |
176 | ```java
177 | @Override
178 | public final void bindToInsertValues(ContentValues values, DefaultModel model) {
179 | if (model.count != null) {
180 | values.put("`count`", model.count);
181 | } else {
182 | values.put("`count`", 55);
183 | }
184 | //...
185 | }
186 | ```
187 |
188 | 我们在运行时插入它的值。这有一定的局限性:
189 | 1. 常量, 纯字符串值
190 | 2. No `Model`, `ModelContainer`, or primitive can use this.
191 | 3. 必须是同一类型的
192 | 4. `String` 类型需要通过进行转义: `"\"something\""`
193 |
--------------------------------------------------------------------------------
/usage/ModelCaching.md:
--------------------------------------------------------------------------------
1 | # 强大的模型缓存
2 | 在这个库模型缓存是很简单的,是非常可扩展的,可获取和使用。
3 |
4 | `ModelCache`是一个用sqlite查询实现的缓存接口,`FlowQueryList`, `FlowCursorList`,或者其他你想使用它的任何地方。
5 |
6 | ## 在表中启用高速缓存
7 | 只要增加 `cachingEnabled = true`在你得`@Table`注解中就可以启用表的高速缓存。要启用类缓存多列`@PrimaryKey`,你_必须_定义一个`@MultiCacheField`对象(下文解释)。
8 |
9 | 当查询在数据库运行时,它将在缓存中存储模型的实例,并且缓存是一个有效的内存管理单独负责的。
10 |
11 | 有几种缓存方式:
12 | There are a few kinds of caches supported out the box:
13 | 1. `ModelLruCache` -> 使用LruCache, Lru规则自动对内存进行管理。
14 | 2. `SimpleMapCache` -> 简单存储models在预定容量的`Map`中(默认为HashMap中)。
15 | 3. `SparseArrayBasedCache` -> 一个基于`SparseArray`下的int->object key/value 类型。它适用于任何_数量_的后代或基本对应(Integer, Double, Long等),或`MulitCacheConverter`返回相同的密钥类型。
16 |
17 | **注意** 如果你运行一个带有字段的 `SELECT` ,你也可以缓存整个`Model` 。强烈建议只加载在这种情况下全款,因为缓存机制将弥补最效率的问题。
18 |
19 | 默认的缓存是 `SimpleMapCache`。你可以在 `@Table`指定 `cacheSize()` 来设置默认缓存的内容的大小。一旦指定自定义缓存,此参数无效。
20 |
21 | 要使用自定义缓存, 在`Model`类中指定缓存:
22 |
23 | ```java
24 | @ModelCacheField
25 | public static ModelCache modelCache = new SimpleMapCache<>();
26 | ```
27 |
28 | 该 `@ModelCacheField` 必须是公共静态。
29 |
30 | 作为3.0,现在DBFlow从缓存加载时巧妙地重新加载`@ForeignKey` 的关系。
31 |
32 | ### 缓存到底是如何工作
33 | 1.每个`@Table`/`Model`类都有其自己的缓存,它们表与表和父类与之类之间不共享。
34 | 2. 它“拦截”查询运行并引用缓存(下面解释)。
35 | 3. 当表中使用了任何包含 `Insert`, `Update`, 或者 `Delete` 方法,将强烈建议不要进行缓存,当运行这些方法后,模型作为缓存将不会更新(因为效率和性能方面的原因)。如果您需要运行这些操作,一个简单的`FlowManager.getModelAdapter(MyTable.class).getModelCache().clear()` 运行后,查询的缓存将失效,它将会继续更新其信息。
36 | 4. 从缓存中修改对象遵循Java引用的规则:在一个线程中更改字段值可能导致您的应用程序数据数据不一致,直到`save()`, `insert()` or `update()`方法运行,才会重新到数据库加载正确的数据。更改任何字段直接从缓存中修改对象(当从它直接加载),所以多加留意。
37 |
38 | 当通过包装语言运行查询,DBFlow将:
39 | 1. 运行查询,从而产生一个`游标`
40 | 2. 通过`游标`检索主键列值
41 | 3. 如果组合键是在高速缓存中,我们:
42 | 1. 刷新关系,如@ForeignKey(如果存在的话)。_提示:_通过表缓存使此更快地实现这一目。
43 | 2. 然后返回缓存的对象。
44 | 4. 如果对象不存在,我们从DB加载完整的对象,和随后的查询到相同的对象将从缓存返回对象(直到它驱逐或从高速缓存清除。)
45 |
46 | ### 多主键缓存
47 | 在3.0,DBFlow支持的高速缓存的多个主密钥。它_需要_那些有一个以上的主键的模型定义一个`@MultiCacheField`:
48 |
49 | ```java
50 | @Table(database = TestDatabase.class, cachingEnabled = true)
51 | public class MultipleCacheableModel extends BaseModel {
52 |
53 | @MultiCacheField
54 | public static IMultiKeyCacheConverter multiKeyCacheModel = new IMultiKeyCacheConverter() {
55 |
56 | @Override
57 | @NonNull
58 | public String getCachingKey(@NonNull Object[] values) { // in order of the primary keys defined
59 | return "(" + values[0] + "," + values[1] + ")";
60 | }
61 | };
62 |
63 | @PrimaryKey
64 | double latitude;
65 |
66 | @PrimaryKey
67 | double longitude;
68 |
69 | @ForeignKey(references = {@ForeignKeyReference(columnName = "associatedModel",
70 | columnType = String.class, foreignKeyColumnName = "name", referencedFieldIsPackagePrivate = true)})
71 | TestModel1 associatedModel;
72 |
73 | }
74 | ```
75 |
76 | 返回类型可以是任何东西,要`ModelCache`定义的类支持返回类型。
77 |
78 | ### FlowCursorList + FlowQueryList
79 | 在`@Table`/`Model`相关缓存中,`FlowCursorList` 和 `FlowQueryList` 利用单独 的`ModelCache`,该覆盖默认的缓存机制:
80 |
81 | ```java
82 |
83 | @Override
84 | protected ModelCache extends BaseCacheableModel, ?> getBackingCache() {
85 | return new MyCustomCache<>();
86 | }
87 | ```
88 |
89 | ### 自定义缓存
90 | 只要你想的话,你可以创建自己的缓存并使用它。
91 |
92 | 一个从支持库复制的`LruCache`缓存使用例子:
93 | An example cache is using a copied `LruCache` from the support library:
94 |
95 | ```java
96 |
97 | public class ModelLruCache extends ModelCache>{
98 |
99 | public ModelLruCache(int size) {
100 | super(new LruCache(size));
101 | }
102 |
103 | @Override
104 | public void addModel(Object id, ModelClass model) {
105 | if(id instanceof Number) {
106 | synchronized (getCache()) {
107 | Number number = ((Number) id);
108 | getCache().put(number.longValue(), model);
109 | }
110 | } else {
111 | throw new IllegalArgumentException("A ModelLruCache must use an id that can cast to" +
112 | "a Number to convert it into a long");
113 | }
114 | }
115 |
116 | @Override
117 | public ModelClass removeModel(Object id) {
118 | ModelClass model;
119 | if(id instanceof Number) {
120 | synchronized (getCache()) {
121 | model = getCache().remove(((Number) id).longValue());
122 | }
123 | } else {
124 | throw new IllegalArgumentException("A ModelLruCache uses an id that can cast to" +
125 | "a Number to convert it into a long");
126 | }
127 | return model;
128 | }
129 |
130 | @Override
131 | public void clear() {
132 | synchronized (getCache()) {
133 | getCache().evictAll();
134 | }
135 | }
136 |
137 | @Override
138 | public void setCacheSize(int size) {
139 | getCache().resize(size);
140 | }
141 |
142 | @Override
143 | public ModelClass get(Object id) {
144 | if(id instanceof Number) {
145 | return getCache().get(((Number) id).longValue());
146 | } else {
147 | throw new IllegalArgumentException("A ModelLruCache must use an id that can cast to" +
148 | "a Number to convert it into a long");
149 | }
150 | }
151 | }
152 | ```
153 |
--------------------------------------------------------------------------------
/demos/DBFlowDemo/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/usage/GettingStarted.md:
--------------------------------------------------------------------------------
1 | # 入门
2 |
3 | 在本节中,我们介绍如何构建一个简单的数据库,表,还有如何建立Model之间的关系。
4 |
5 | **蚁后**:我们想知道蚁群数据是怎么保存的。我们要跟踪和标记所有蚂蚁的特定群体以及每个蚁后。
6 |
7 | 我们有这样的关系:
8 |
9 | ```
10 |
11 | Colony (1..1) -> Queen (1...many)-> Ants//1对1,1对多
12 | ```
13 |
14 |
15 | ## 设置DBFlow
16 |
17 | 要初始化DBFlow,放置在这段代码( FlowManager.init(this);)在你自定义的 `Application` 类中(推荐):
18 |
19 | ```java
20 |
21 | public class ExampleApplication extends Application {
22 |
23 | @Override
24 | public void onCreate() {
25 | super.onCreate();
26 | FlowManager.init(this);
27 | }
28 |
29 | }
30 | ```
31 | 别担心,这只是初始化一次,它会守住只有应用程序,即使使用其他`Context`初始化。
32 |
33 | 最后,定义添加到清单(对应您的自定义应用程序的名称):
34 |
35 | ```xml
36 |
37 |
40 |
41 | ```
42 |
43 |
44 | ## 定义我们的数据库
45 |
46 | 在DBFlow,一个 `@Database` 是一个占位符,这个占位符可以生产子类对象 `BaseDatabaseDefinition`, `BaseDatabaseDefinition`连接所有表,ModelAdapter,Views,Queries还有更多其下的对象。所有连接都在预编译的时候完成,所以没有搜索,反射,和任何其他能减慢您的应用程序的运行时间的影响。
47 |
48 | 在这个例子中,我们需要定义我们要把蚁群保存到哪里(定义数据库):
49 |
50 | ```java
51 |
52 | @Database(name = ColonyDatabase.NAME, version = ColonyDatabase.VERSION)
53 | public class ColonyDatabase {
54 |
55 | public static final String NAME = "Colonies";
56 |
57 | public static final int VERSION = 1;
58 | }
59 | ```
60 |
61 | 对于最佳实践,我们声明的常量`NAME`和 `VERSION`为public,以便于我们以后可以使用它。
62 |
63 | _Note:_ 如果你想使用[SQLCipher(数据库加密)](https://www.zetetic.net/sqlcipher/) 请阅读 [setup here](usage/SQLCipherSupport.md)
64 |
65 |
66 | ## 创建我们的表和建立关系
67 |
68 | 现在,我们有了保存蚁群数据的地方了(ColonyDatabase),我们需要明确定义`Model` 来保存数据和展示数据
69 |
70 |
71 | ### 蚁后表(The Queen Table)
72 |
73 | 我们将自上而下的理解关系。每个蚁群只有一个皇后。我们定义数据库对象使用ORM(对象关系映射)模型。我们需要做的是在我们的`Model`定义我们每个需要保存到数据库的字段。
74 |
75 | 在DBFlow,任何要使用ORM实现数据库交互的都必须实现接口`Model`(也就是说如果你的数据库表一定要实现`Model`接口)。这样做的原因是统一接口balabala。。。。。为了方便起见,我们可以extends `BaseModel`(`BaseModel` 已经实现了 `Model`接口)
76 |
77 | 要正确定义一个表,我们必须:
78 |
79 | 1. @Table注释标记类
80 |
81 | 2. 将表到正确的数据库,例如`ColonyDatabase`
82 |
83 | 3. 至少定义一个主键
84 |
85 | 4. 类及其所有数据库中的列(model中的变量)必须用`private`或`public`,`private`的必须有(getter和setter方法)。这样从DBFlow生成的类可以访问它们。
86 |
87 | 我们可以这样定义一个基础的 `Queen` 表:
88 |
89 | ```java
90 |
91 | @Table(database = ColonyDatabase.class)
92 | public class Queen extends BaseModel {
93 |
94 | @PrimaryKey(autoincrement = true)
95 | long id;
96 |
97 | @Column
98 | String name;
99 |
100 | }
101 | ```
102 |
103 | 因此,我们有一个蚁后的定义后,现在我们需要为蚁后定义一个蚁群。
104 |
105 |
106 | ### The Colony(蚁群)
107 |
108 | ```java
109 | @ModelContainer // more on this later.
110 | @Table(database = ColonyDatabase.class)
111 | public class Colony extends BaseModel {
112 |
113 | @PrimaryKey(autoincrement = true)
114 | long id;
115 |
116 | @Column
117 | String name;
118 |
119 | }
120 | ```
121 |
122 | 现在,我们有一个`Queen`和`Colony`,我们要建立一个1对1的关系。我们希望,当数据被删除,例如,如果发生火灾,破坏蚁群 `Colony`。当蚁群被破坏,我们假设女王`Queen`不再存在,所以我们要为 `Colony`“杀”了`Queen`,使其不再存在。
123 |
124 | ### 1-1 关系
125 | 为了建立他们的关系,我们将会定义一个外键作为Child:
126 |
127 | ```java
128 |
129 | @ModelContainer
130 | @Table(database = ColonyDatabase.class)
131 | public class Queen extends BaseModel {
132 |
133 | //...previous code here
134 |
135 | @Column
136 | @ForeignKey(saveForeignKeyModel = false)
137 | Colony colony;
138 |
139 | }
140 | ```
141 | 为`Model`定义为外键的时候,查询数据库时候,该外键的值会自动加载(查询`Queen`的时候,对应的`Colony`会自动被加载)。出于性能方面的原因,我们默认`saveForeignKeyModel=false` ,目的是保存 `Queen`不会自动保存 `Colony` 。
142 |
143 | 如果你想保持这种配对完好,设置`saveForeignKeyModel=true`。
144 |
145 | 在3.0,我们不再需要明确地定义`@ForeignKeyReference` 每个引用列。DBFlow会自动将它们添加到表定义中,基于引用表的`@PrimaryKey`。它们将出现在格式`{foreignKeyFieldName}_{referencedColumnName}`。(如上外键`colony`的格式是:`colony_id`)
146 |
147 |
148 | ### 蚂蚁表 + 一对多
149 | 现在,我们有一个蚁群`Colony` 与蚁后 `Queen` 属于它,我们需要一些蚂蚁服侍她!
150 |
151 |
152 | ```java
153 |
154 | @Table(database = ColonyDatabase.class)
155 | public class Ant extends BaseModel {
156 |
157 | @PrimaryKey(autoincrement = true)
158 | long id;
159 |
160 | @Column
161 | String type;
162 |
163 | @Column
164 | boolean isMale;
165 |
166 | @ForeignKey(saveForeignKeyModel = false)
167 | ForeignKeyContainer queenForeignKeyContainer;
168 |
169 | /**
170 | * Example of setting the model for the queen.
171 | */
172 | public void associateQueen(Queen queen) {
173 | queenForeignKeyContainer = FlowManager.getContainerAdapter(Queen.class).toForeignKeyContainer(queen);
174 | }
175 | }
176 | ```
177 |
178 | 我们有 `type`,它可以是 "worker", "mater", 或 "other"。此外,如果蚂蚁还有男女之分。
179 |
180 | 在这种情况下,我们使用 `ForeignKeyContainer`,因为我们可以有成千上万的蚂蚁。出于性能的考虑,`Queen`将会被“延迟加载的”,只有我们调用`toModel()`,才会查询数据库找出对应的 `Queen`。与此说,为了在`ForeignKeyContainer`上设置适当的值,你应该通过调用其生成的方法(`FlowManager.getContainerAdapter(Queen.class).toForeignKeyContainer(queen)`)为自己转换成 `ForeignKeyContainer` 。
181 |
182 | 由于`ModelContainer`默认情况下不会使用,所以我们必须添加 `@ModelContainer`注释到`Queen` 累中才能使用 `ForeignKeyContainer`。
183 |
184 | 最后,使用`@ForeignKeyContainer`可以防止循环引用。如果这 `Queen` 和 `Colony`互相引用,我们会碰上的StackOverflowError,因为他们都将尝试从数据库加载对方中。
185 |
186 | 接下来,我们通过延迟加载蚂蚁建立“一对多”的关系,因为我们可能有成千上万,甚至是,数以百万计的储存:
187 |
188 | ```java
189 |
190 | @ModelContainer
191 | @Table(database = ColonyDatabase.class)
192 | public class Queen extends BaseModel {
193 | //...
194 |
195 | // needs to be accessible for DELETE
196 | List ants;
197 |
198 | @OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, variableName = "ants")
199 | public List getMyAnts() {
200 | if (ants == null || ants.isEmpty()) {
201 | ants = SQLite.select()
202 | .from(Ant.class)
203 | .where(Ant_Table.queenForeignKeyContainer_id.eq(id))
204 | .queryList();
205 | }
206 | return ants;
207 | }
208 | }
209 | ```
210 |
211 | ``注意``:如果你发现`Ant_Table`报错的时候,跑一下,让库自动生成模板就不会再报错了
212 |
213 | 如果你想给自己懒加载,指定`OneToMany.Method.DELETE`和`SAVE`,代替`ALL`。如果每当女王的数据变化时候,您不希望保存,那么只指定 `DELETE` 和 `LOAD`。
214 |
--------------------------------------------------------------------------------
/usage/SQLQuery.md:
--------------------------------------------------------------------------------
1 | # SQL语句使用包装类
2 |
3 | 在Android SQL,SQL编写是一件不好玩的事,所以为了简单易用,该库提供了一套对SQLite声明的分装,试图使java代码尽可能看上去就像SQLite。
4 |
5 | 在第一部分,我描述如何使用包装类彻底简化代码编写。
6 |
7 |
8 | ## 例
9 | 例如,我们要在`Ant`找到所有类型为“工人”,并为女性的蚂蚁。编写SQL语句是很容易的:
10 |
11 | ```sql
12 |
13 | SELECT * FROM Ant where type = 'worker' AND isMale = 0;
14 | ```
15 |
16 | 我们想用Android的代码来写这一点,SQL数据转换成有用信息:
17 |
18 | ```java
19 |
20 | String[] args = new String[2];
21 | args[0] = "worker";
22 | args[1] = "0";
23 | Cursor cursor = db.rawQuery("SELECT * FROM Ant where type = ? AND isMale = ?", args);
24 | final List ants = new ArrayList();
25 | Ant ant;
26 |
27 | if (cursor.moveToFirst()) {
28 | do {
29 | // get each column and then set it on each
30 | ant = new Ant();
31 | ant.setId(cursor.getLong(cursor.getColumnIndex("id")));
32 | ant.setType(cursor.getString(cursor.getColumnIndex("type")));
33 | ant.setIsMale(cursor.getInt(cursor.getColumnIndex("isMale") == 1);
34 | ant.setQueenId(cursor.getLong(cursor.getColumnIndex("queen_id")));
35 | ants.add(ant);
36 | }
37 | while (cursor.moveToNext());
38 | }
39 | ```
40 |
41 | 这么简短而亲切的简单的查询,但我们为什么要继续写这些语句?
42 |
43 | 如果这样写会发生什么呢:
44 |
45 |
46 | 1. 我们添加或删除列的时候呢?
47 | 2. 在其他表写这样的查询是否每次都要重复写这些代码?或者类似的查询页要重复写这些代码?
48 |
49 | 总之,我们希望我们的代码是可维护,简短,复用性高,并且仍然表现究竟正在发生的事情。在这个库中,这个查询变得非常简单:
50 |
51 | ```java
52 |
53 | // main thread retrieval
54 | List devices = SQLite.select().from(Ant.class)
55 | .where(Ant_Table.type.eq("worker"))
56 | .and(Ant_Table.isMale.eq(false)).queryList();
57 |
58 | // Async Transaction Queue Retrieval (Recommended for large queries)
59 | SQLite.select()
60 | .from(DeviceObject.class)
61 | .where(Ant_Table.type.eq("worker"))
62 | .and(Ant_Table.isMale.eq(false))
63 | .async().queryList(transactionListener);
64 | ```
65 |
66 | 有许多操作在DBFlow得到支持:
67 | 1. SELECT
68 | 2. UPDATE
69 | 3. INSERT
70 | 4. DELETE
71 | 5. JOIN
72 |
73 | ## SELECT语句和检索方法
74 | 一个`SELECT`语句从数据库中检索数据。我们通过检索数据
75 |
76 | 1. 普通的在主线程中 `Select`
77 | 2. 用`TransactionManager` 运行一个 `Transaction` (建议用于大型查询).
78 |
79 | ```java
80 |
81 | // 查询一个List
82 | SQLite.select().from(SomeTable.class).queryList();
83 | SQLite.select().from(SomeTable.class).where(conditions).queryList();
84 |
85 | //查询单个 Model
86 | SQLite.select().from(SomeTable.class).querySingle();
87 | SQLite.select().from(SomeTable.class).where(conditions).querySingle();
88 |
89 | // 从一个表中查询一个list或游标(cursor)
90 | SQLite.select().from(SomeTable.class).where(conditions).queryTableList();
91 | SQLite.select().from(SomeTable.class).where(conditions).queryCursorList();
92 |
93 | // 在ModelContainer查询!
94 | SQLite.select().from(SomeTable.class).where(conditions).queryModelContainer(new MapModelContainer<>(SomeTable.class));
95 |
96 | // 查询 methods
97 | SQLite.select().distinct().from(table).queryList();
98 | SQLite.select().from(table).queryList();
99 | SQLite.select(Method.avg(SomeTable_Table.salary))
100 | .from(SomeTable.class).queryList();
101 | SQLite.select(Method.max(SomeTable_Table.salary))
102 | .from(SomeTable.class).queryList();
103 |
104 | // Transact a query on the DBTransactionQueue
105 | TransactionManager.getInstance().addTransaction(
106 | new SelectListTransaction<>(new Select().from(SomeTable.class).where(conditions),
107 | new TransactionListenerAdapter>() {
108 | @Override
109 | public void onResultReceived(List someObjectList) {
110 | // retrieved here
111 | });
112 |
113 | // Selects Count of Rows for the SELECT statment
114 | long count = SQLite.selectCountOf()
115 | .where(conditions).count();
116 | ```
117 |
118 | ### Order By
119 |
120 | ```java
121 |
122 | // true for 'ASC', false for 'DESC'
123 | SQLite.select()
124 | .from(table)
125 | .where()
126 | .orderBy(Customer_Table.customer_id, true)
127 | .queryList();
128 |
129 | SQLite.select()
130 | .from(table)
131 | .where()
132 | .orderBy(Customer_Table.customer_id, true)
133 | .orderBy(Customer_Table.name, false)
134 | .queryList();
135 | ```
136 |
137 | ### Group By
138 |
139 | ```java
140 | SQLite.select()
141 | .from(table)
142 | .groupBy(Customer_Table.customer_id, Customer_Table.customer_name)
143 | .queryList();
144 | ```
145 |
146 | ### HAVING
147 |
148 | ```java
149 | SQLite.select()
150 | .from(table)
151 | .groupBy(Customer_Table.customer_id, Customer_Table.customer_name))
152 | .having(Customer_Table.customer_id.greaterThan(2))
153 | .queryList();
154 | ```
155 |
156 | ### LIMIT + OFFSET
157 |
158 | ```java
159 | SQLite.select()
160 | .from(table)
161 | .limit(3)
162 | .offset(2)
163 | .queryList();
164 | ```
165 |
166 | ## UPDATE语句
167 | 这里有2中更耐心数据库的方法:
168 |
169 | 1. 调用 `SQLite.update()`或者使用 `Update` 类
170 | 2. 运行 `事务` 使用 `事务管理器` (推荐线程安全的,但是看到的变化是异步)。
171 |
172 | 在本节中,我们将从数据库描述批量更新数据
173 |
174 | 在我们对前面蚂蚁的例子中,我们要改变我们目前所有的男性“worker”蚂蚁为“other”蚂蚁,因为他们偷懒不工作了。
175 | From our earlier example on ants, we want to change all of our current male "worker" ants into "other" ants because they became lazy and do not work anymore.
176 |
177 | 使用本地SQL:
178 |
179 | ```sql
180 |
181 | UPDATE Ant SET type = 'other' WHERE male = 1 AND type = 'worker';
182 | ```
183 |
184 | 使用DBFlow:
185 |
186 | ```java
187 |
188 | // Native SQL wrapper
189 | Where update = SQLite.update(Ant.class)
190 | .set(Ant_Table.type.eq("other"))
191 | .where(Ant_Table.type.is("worker"))
192 | .and(Ant_Table.isMale.is(true));
193 | update.queryClose();
194 |
195 | // TransactionManager (more methods similar to this one)
196 | TransactionManager.getInstance().addTransaction(new QueryTransaction(DBTransactionInfo.create(BaseTransaction.PRIORITY_UI), update);
197 | ```
198 |
199 | ## DELETE语句
200 |
201 | ```java
202 |
203 | // Delete a whole table
204 | Delete.table(MyTable.class, conditions);
205 |
206 | // Delete multiple instantly
207 | Delete.tables(MyTable1.class, MyTable2.class);
208 |
209 | // Delete using query
210 | SQLite.delete(MyTable.class)
211 | .where(DeviceObject_Table.carrier.is("T-MOBILE"))
212 | .and(DeviceObject_Table.device.is("Samsung-Galaxy-S5"))
213 | .query();
214 | ```
215 |
216 | ## JOIN声明
217 | 作为参考, ([JOIN examples](http://www.tutorialspoint.com/sqlite/sqlite_using_joins.htm)).
218 |
219 | `JOIN` 语句能很好地结合很多一对多的关系。
220 | 如果查询返回非表字段,不能映射到现有的对象,
221 | If your query returns non-table fields and cannot map to an existing object,
222 | 请参阅有关 [查询模式](usage/QueryModels.md)
223 |
224 | 例如,我们有一个表名为`客户`,另一个名为`预订`。
225 |
226 | ```SQL
227 | SELECT FROM `Customer` AS `C` INNER JOIN `Reservations` AS `R` ON `C`.`customerId`=`R`.`customerId`
228 | ```
229 |
230 | ```java
231 | // use the different QueryModel (instead of Table) if the result cannot be applied to existing Model classes.
232 | List customers = new Select()
233 | .from(Customer.class).as("C")
234 | .join(Reservations.class, JoinType.INNER).as("R")
235 | .on(Customer_Table.customerId
236 | .withTable(new NameAlias("C"))
237 | .eq(Reservations_Table.customerId.withTable("R"))
238 | .queryCustomList(CustomTable.class);
239 | ```
240 |
241 | 该 `IProperty.withTable()` 方法会在前面加上 `NameAlias` 或 `Table` 别名到 `IProperty`查询, 方便连接查询:
242 |
243 | ```sqlite
244 | SELECT EMP_ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT
245 | ON COMPANY.ID = DEPARTMENT.EMP_ID
246 | ```
247 |
248 | 在 DBFlow:
249 |
250 | ```java
251 | SQLite.select(Company_Table.EMP_ID, Company_Table.DEPT)
252 | .from(Company.class)
253 | .leftOuterJoin(Department.class)
254 | .on(Company_Table.ID.withTable().eq(Department_Table.EMP_ID.withTable()))
255 | .queryList();
256 | ```
257 |
--------------------------------------------------------------------------------