GreenDao3.2.2 使用
一、介紹
GreenDAO是一個開源的安卓ORM框架,。它減輕開發人員處理低級數據庫需求,同時節省開發時間。 SQLite是一個內嵌的關係數據庫,編寫SQL和解析查詢結果是相當乏味和耗時的任務。通過將Java對象映射到數據庫表(稱爲ORM,“對象/關係映射”),GreenDAO可以將它們從這些映射中釋放出來,這樣,您可以使用簡單的面向對象的API來存儲,更新,刪除和查詢數據庫。簡單的,GreenDAO 是一個將對象映射到 SQLite 數據庫中的輕量且快速的 ORM 解決方案。
與2.0的區別:GreenDao 3.0採用註解的方式來定義實體類,通過gradle插件生成相應的代碼。您可以使用greenDAO Gradle插件,無需任何其他配置,但至少要設置schema的版本等;
二、使用前的配置
使用前你需要添加greenDAO Gradle插件並添加greenDAO庫:
做法:首先在你的工程的gradle文件中添加相應的依賴
buildscript { repositories { jcenter() mavenCentral() // add repository } dependencies { classpath 'com.android.tools.build:gradle:3.1.1' classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin } }
然後在你具體使用的app modules的gradle文件裏添加相關的插件依賴和函數庫
apply plugin: 'com.android.application' apply plugin: 'org.greenrobot.greendao' // apply plugin dependencies { implementation 'org.greenrobot:greendao:3.2.2' // add library
這樣算是配置完成啦
三、使用GreenDao建模實體
首先我們看看官方的文檔:
要在項目中使用greenDAO,您需要創建一個實體模型來表示應用程序中的持久性數據。然後,基於該模型, greenDAO爲DAO類生成Java代碼。
意思是你需要建立實體類去代表你要在數據庫中要生成的表的數據。GreenDao可以通過你建立的實體類去生成相應的表,並根據你的實體類對象爲你自動生成操作數據庫的相關java類,而這些的實現,GreenDao3.0後是通過註解的形式實現的。
注意: 我們無需任何其他配置即可開始使用greenDAO Gradle插件。不過,應該設置架構版本:
在工程的gradle文件中添加相應設置架構版本的代碼:
android { ... } greendao { schemaVersion 2 // daoPackage "com.example.model" // set package of generated classes }
此外,greendao配置元素支持許多配置選項:
- schemaVersion:數據庫模式的當前版本。這是使用的 * OpenHelpers類模式版本之間遷移。如果更改實體/數據庫架構,則必須增加該值。默認爲1。
- daoPackage:生成的DAO,DaoMaster和DaoSession的軟件包名稱。 默認爲源實體的程序包名稱。
- targetGenDir:應將生成的源存儲在的位置。 默認爲生成目錄內生成的源文件夾( 建立/ 生成/ 源/ greendao)。
- generateTests: 設置爲true以自動生成單元測試。
- targetGenDirTests: 應將生成的單元測試存儲在的基本目錄。默認爲 src / androidTest / java。
好啦我們開始創建我們的實體類啦:
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "USERNAME")
private String name;
@NotNull
private int repos;
@Transient
private int tempUsageCount;
}
這是我們創建的實體類,你會發現代碼裏面包含着註釋,那這些註釋的作用是什麼呢?
@Entity註解打開Java類 用戶到數據庫支持的實體。這還將指示greenDAO生成必要的代碼(例如DAO)。
注意:僅支持Java類。如果您喜歡Kotlin等其他語言,則您的實體類必須仍然是Java。
Entity就是實體的意思這個註釋可以讓GreenDao識別, 將我們的java普通類變爲一個能夠被greenDAO識別的數據庫類型的實體類;
@Entity 不需要任何其他參數也可以,但是你也可以使用**@Entity**配置一些細節 用法如下:
@Entity(
// 如果您有多個模式,可以告訴greenDAO
// 實體屬於哪個模式(選擇任何字符串作爲名稱)。
schema = "myschema",
// 標記使一個實體“活動”:活動實體有更新
// 刪除和刷新方法
active = true,
//指定數據庫中表的名稱。
// 默認情況下,名稱基於實體類名。
nameInDb = "AWESOME_USERS",
//定義跨越多個列的索引。
indexes = {
@Index(value = "name DESC", unique = true)
},
//標記DAO是否應該創建數據庫表(默認爲true)。
//如果你有多個實體映射到一個表,
//或者在greenDAO之外創建表。
createInDb = false,
//是否應該生成一個all properties構造函數。
//總是需要一個無參數的構造函數。
generateConstructors = true,
//如果缺少屬性的getter和setter是否應該生成。
generateGettersSetters = true
)
public class User {
...
}
@Id註釋選擇 long / Long屬性作爲實體ID。用數據庫術語來說,它是主鍵。參數autoincrement 是使ID值不斷增加(不重用舊值)的標誌。
@Property允許您定義一個非默認列名,該屬性映射到該列名。如果不存在,greenDAO將以類似於SQL的方式使用字段名稱(大寫字母,下劃線而不是駝峯字母,例如 customName將變爲 CUSTOM_NAME)。
@NotNull使該屬性在數據庫端成爲“ NOT NULL”列。通常,使用@NotNull標記原始類型(long,int,short,byte)是有意義的,同時使用包裝類(Long,Integer,Short,Byte)具有可空值。
@Transient標記要從持久性中排除的屬性。將它們用於臨時狀態等。或者,您也可以使用Java中的transient關鍵字。
主鍵限制
當前,實體必須具有 long或 Long屬性作爲其主鍵。這是Android和SQLite的推薦做法。
意思就是表的主鍵必須是long或 Long類型的但是我們可以通過爲其他字段添加一個唯一不重複的索引來使這個字段擁有和主鍵一樣的唯一標示性,那麼這個字段雖然不是主鍵,卻可以像主鍵一樣的使用。
要解決此問題,請將您的key屬性定義爲其他屬性,但爲其創建一個唯一索引:
@Entity public class User { @Id private Long id; @Index (unique = true) private String name; }
在屬性上使用**@Index**爲相應的數據庫列創建數據庫索引。使用以下參數進行自定義:
-
name:如果您不喜歡greenDAO爲索引生成的默認名稱,則可以在此處指定您的名稱。
-
unique:向索引添加UNIQUE約束,強制所有值都是唯一的。
greenDAO嘗試使用合理的默認值,因此開發人員不必每次都進行配置。
例如,數據庫端的表名和列名是從實體名和屬性名派生的。代替Java中使用的駝峯式樣式,默認數據庫名稱使用大寫字母,使用下劃線分隔單詞。
例如,名爲creationDate的屬性 將成爲數據庫列 CREATION_DATE。
最後我們通過註釋聲明啦一個實體類,我們點擊Android studio 的Build------>make project
然後我們就會發現在我們的module中自動生成啦一些東西,並且我們的實體類也多啦get set的方法。
到這裏我們就用GreenDao構造啦實體。下面介紹一下生成的這幾個類:
這裏要解釋一下生成的三個核心類的作用:
DaoMaster:DaoMaster保存數據庫對象(SQLiteDatabase)並管理特定模式的DAO類(而不是對象)。 它具有靜態方法來創建表或將它們刪除。 其內部類OpenHelper和DevOpenHelper是在SQLite數據庫中創建模式的SQLiteOpenHelper實現。一個DaoMaster就代表着一個數據庫的連接。
DaoSession:管理特定模式的所有可用DAO對象,您可以使用其中一個getter方法獲取。 DaoSession還爲實體提供了一些通用的持久性方法,如插入,加載,更新,刷新和刪除。 DaoSession可以讓我們使用一些Entity的基本操作和獲取Dao操作類,DaoSession可以創建多個,每一個都是屬於同一個數據庫連接的。
XxxDAO:數據訪問對象(DAO)持續存在並查詢實體。 對於每個實體,GreenDAO生成一個DAO。 它比DaoSession有更多的持久化方法,例如:count,loadAll和insertInTx。
四、使用GreenDao的表關係註解
我們知道數據庫表可以使用1:1、1:N或N:M關係相互關聯。通過主外鍵的形式把多張表進行聯繫。
在GreenDao中仍然是通過註解的形式實現的。
一對一關係建模:
所述**@ToOne**註釋定義一個相對於另一實體(一個實體對象)。將其應用於持有另一個實體對象的屬性。
在內部,greenDAO需要一個額外的屬性,該屬性指向目標實體的ID,該屬性由joinProperty參數指定。如果不存在此參數,則會自動創建一個附加列來保存鍵。
實例代碼:我們創建兩個實體類,一個Son類,一個Father類。假設一個父親對應一個兒子,一個兒子對應一個父親。
/**
* Created by zhongzai on 2019/10/25
*/
@Entity
public class Father {
@Id
private Long _id;
@Property(nameInDb = "NAME")
private String name;
@Property(nameInDb = "age")
private int age;
}
/**
* Created by zhongzai on 2019/10/25
*/
@Entity
public class Son {
@Id
private Long _id;
private long fatherId;
@ToOne(joinProperty = "fatherId")
private Father father;
}
對多關係建模
@ToMany定義與一組其他實體(多個實體對象)的關係。將此屬性應用於代表目標實體列表的屬性 。所引用的實體必須具有一個或多個指向擁有@ToMany的實體的屬性。
有三種可能性可以指定關係映射,請僅使用其中一種:
- referencedJoinProperty參數:指定目標實體中指向該實體ID的“外鍵”屬性的名稱。
@Entity public class Customer { @Id private Long id; @ToMany(referencedJoinProperty = "customerId") @OrderBy("date ASC") private List<Order> orders; } @Entity public class Order { @Id private Long id; private Date date; private long customerId; }
- joinProperties參數:對於更復雜的關係,您可以指定**@JoinProperty**批註的列表。每個@JoinProperty都需要原始實體中的源屬性和目標實體中的引用屬性。
@Entity public class Customer { @Id private Long id; @Unique private String tag; @ToMany(joinProperties = { @JoinProperty(name = "tag", referencedName = "customerTag") }) @OrderBy("date ASC") private List<Site> orders; } @Entity public class Order { @Id private Long id; private Date date; @NotNull private String customerTag; }
- @JoinEntity批註:如果您正在執行涉及另一個聯接實體/表的N:M(多對多)關係,則將此附加批註放在屬性上。
@Entity public class Product { @Id private Long id; @ToMany @JoinEntity( entity = JoinProductsWithOrders.class, sourceProperty = "productId", targetProperty = "orderId" ) private List<Order> ordersWithThisProduct; } @Entity public class JoinProductsWithOrders { @Id private Long id; private Long productId; private Long orderId; } @Entity public class Order { @Id private Long id; }
還有其他模式:參考官方文檔 http://greenrobot.org/greendao/documentation/relations/
五、使用GreenDao實現數據庫的增刪改查
創建一個類用來管理數據庫的創建,數據庫表的創建、增刪改查的操作以及數據庫的升級
package com.example.sqlite_greendao.zhongzai;
import android.content.Context;
import com.greendao.gen.DaoMaster;
import com.greendao.gen.DaoSession;
/**
* 創建數據庫、創建數據庫表、包含增刪改查的操作以及數據庫的升級
* Created by zhongzai on 2019/10/25
*/
public class MyDaoManager {
private static final String DB_NAME = "mydbtest";
private Context context;
private static MyDaoManager manager = new MyDaoManager();
private static DaoMaster master;
private static DaoMaster.DevOpenHelper helper;
private static DaoSession daoSession;
/**
* 使用單例模式獲得操作數據庫對象
*/
public static MyDaoManager getInstance() {
return manager;
}
public void init(Context context) {
this.context = context;
}
/**
* 判斷是否有存在數據庫,如果沒有則創建
*/
public DaoMaster getDaoMaster() {
if (master == null) {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
master = new DaoMaster(helper.getWritableDatabase());
}
return master;
}
/**
* 對數據庫的添加、刪除、修改、查詢操作,僅僅是一個接口不是對象
*/
public DaoSession getDaoSession() {
if (daoSession == null) {
if (master == null) {
master = getDaoMaster();
}
daoSession = master.newSession();
}
return daoSession;
}
/**
* 關閉所有的操作,數據庫開啓後,使用完畢要關閉
*/
public void closeConnection() {
if (helper != null) {
helper.close();
helper = null;
}
if (daoSession != null) {
daoSession.clear();
daoSession = null;
}
}
}
爲father表創建一個工具類用來實現對father表的增刪改查
package com.example.sqlite_greendao.zhongzai;
import android.content.Context;
import com.example.sqlite_greendao.Father;
import com.greendao.gen.FatherDao;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.List;
/**
* Created by zhongzai on 2019/10/25
*/
public class FatherDaoUtils {
private MyDaoManager mManager;
public FatherDaoUtils(Context context) {
mManager = mManager.getInstance();
mManager.init(context);
}
/**
* 完成father記錄的插入,如果表未創建,先創建father表
*/
public boolean insert(Father father) {
boolean flag = false;
if (mManager.getDaoSession().getFatherDao().insert(father) == -1) {
flag = false;
} else {
flag = true;
}
return flag;
}
/**
* 修改一條數據
*/
public boolean updateFather(Father father) {
boolean flag = false;
try {
mManager.getDaoSession().update(father);
flag = true;
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* 刪除單條記錄
*/
public boolean deleteFather(Father father) {
boolean flag = false;
try {
//按照id刪除
mManager.getDaoSession().delete(father);
flag = true;
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* 刪除所有記錄
*/
public boolean deleteAll() {
boolean flag = false;
try {
//按照id刪除
mManager.getDaoSession().deleteAll(Father.class);
flag = true;
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* 查詢所有記錄
*/
public List<Father> queryAll() {
return mManager.getDaoSession().loadAll(Father.class);
}
/**
* 根據主鍵id查詢記錄
*/
public Father queryItemById(long key) {
Father father = mManager.getDaoSession().load(Father.class, key);
return father;
}
/**
* 使用queryBuilder進行查詢
*/
public List<Father> queryItemByQueryBuilder(long id) {
QueryBuilder<Father> queryBuilder = mManager.getDaoSession().queryBuilder(Father.class);
return queryBuilder.where(FatherDao.Properties._id.eq(id)).list();
}
/**
*關閉資源
*/
public void close() {
mManager.closeConnection();
}
}
在activity中調用:
調用插入:
switch (view.getId()) {
case R.id.insert:
for (int i = 1; i <= 10; i++) {
//插入一條記錄
if (fatherDaoUtils.insert(new Father(Long.valueOf(i + ""), "demo" + i, 20))) {
Log.d("myGreenLog", "插入成功" + i);
}
}
break;
調用更新:
case R.id.update:
for (int i = 1; i <= 4; i++) {
//更新一條記錄
if (fatherDaoUtils.updateFather(new Father(Long.valueOf(i + ""), "demo" + i, 20 + i))) {
Log.d("myGreenLog", "更新成功" + i);
}
}
break;
調用刪除:
case R.id.delete:
for (int i = 1; i <= 2; i++) {
//刪除一條記錄
if (fatherDaoUtils.deleteFather(new Father(Long.valueOf(i + ""), "demo" + i, 20 + i))) {
Log.d("myGreenLog", "刪除成功" + i);
}
}
break;
調用刪除所有:
case R.id.deleteall:
//刪除所有記錄
fatherDaoUtils.deleteAll();
Log.i("myGreenLog", "刪除成功");
break;
調用查詢:
case R.id.selectItem:
for (int i = 1; i <= 10; i++) {
//查詢一條記錄
Father father = fatherDaoUtils.queryItemById(Long.valueOf(i + ""));
if (father != null) {
Log.d("myGreenLog", "查詢成功" + father.toString());
} else {
Log.d("myGreenLog", "查詢失敗" + i);
}
}
break;
調用查詢所有:
case R.id.selectAll:
Log.i("myGreenLog", fatherDaoUtils.queryAll().toString());
break;
調用queryBuilder查詢:
case R.id.queryBuilder:
List<Father> List = fatherDaoUtils.queryItemByQueryBuilder(10);
for (Father father : List) {
Log.i("myGreenLog", father.toString());
}
break;