greenDao使用指南-1

GreenDao

GreenDao是一個高效的數(shù)據(jù)庫訪問ORM框架,節(jié)省了自己編寫SQL的時間,快速的增刪查改等操作。

介紹就不多說,直接介紹重點吧?。。∈紫萷o一個github的地址:https://github.com/greenrobot/greenDAO

配置GreenDao

// In your root build.gradle file:
buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}
 
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
 
dependencies {
    compile 'org.greenrobot:greendao:3.2.2' // add library
}

注意咯,一個是添加在工程的build.gradle,一個是添加到module的build.gradle文件中.

build.gradlel里面對greenDao進(jìn)行配置。配置之后就搭建好了greenDao的環(huán)境,可以自動生成相關(guān)的類。

然后你需要配置greenDao的數(shù)據(jù)庫版本號以及自動生成的包名的路徑,當(dāng)然路徑可選擇性的配置。

android{
    ...
}

greendao{
    schemaVersion 2 // 數(shù)據(jù)庫版本號
    daoPackage  'com.doris.sample.greendao'//greenDao 自動生成的代碼保存的包名
    targetGenDir   'src/main/java' //自動生成的代碼存儲的路徑,默認(rèn)是 build/generated/source/greendao.
    generateTests false //true的時候自動生成測試單元
    targetGenDirTests: 測試單元的生成目錄默認(rèn)是 src/androidTest/java
}

接下來你定義自己的entity并且make project就可以開始對數(shù)據(jù)庫進(jìn)行操作啦。

下面對greenDao的相關(guān)知識點進(jìn)行介紹:

注釋

greenDAO 3 用注釋去schemas 和實體類 entities.例子如下:

@Entity(nameInDb = "user_info",indexes = {
                @Index(value = "name DESC", unique = true)
        },)
public class User {
    @Id
    private Long id;
 
    @Property(nameInDb = "USERNAME") @NotNull
    private String name;
 
    @Transient
    private int tempUsageCount; // not persisted
 
   // getters and setters for id and user ...
}

@Entity將一個Java類轉(zhuǎn)變成一個實體類。greenDao會根據(jù)這個生成對應(yīng)的代碼。PS: 必須是java類,kotlin不支持。

在Entity中我們可以配置許多信息,比如nameInDb是聲明了該表數(shù)據(jù)庫中的表名。
indexes 用于建立索引,索引的應(yīng)用場景可用于,當(dāng)你的表有多個主鍵的時候,來標(biāo)志一條數(shù)據(jù)的唯一性,配合unique。
當(dāng)然上面兩個只是我們常用的屬性,還有幾個其他屬性,目前我還沒有用到:
schema = "myschema", 當(dāng)你有多個schema,用這個屬性來告訴數(shù)據(jù)庫當(dāng)前entity屬于哪個schema。
active = true,用于標(biāo)志某個entity是否是active的,active的實體類有刪改的方法。默認(rèn)是fale, 為true的時候會自動生成下面的代碼在entity里面:

 /**
    * Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
    * Entity must attached to an entity context.
    */
   @Generated(hash = 128553479)
   public void delete() {
       if (myDao == null) {
           throw new DaoException("Entity is detached from DAO context");
       }
       myDao.delete(this);
   }

   /**
    * Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
    * Entity must attached to an entity context.
    */
   @Generated(hash = 1942392019)
   public void refresh() {
       if (myDao == null) {
           throw new DaoException("Entity is detached from DAO context");
       }
       myDao.refresh(this);
   }

   /**
    * Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
    * Entity must attached to an entity context.
    */
   @Generated(hash = 713229351)
   public void update() {
       if (myDao == null) {
           throw new DaoException("Entity is detached from DAO context");
       }
       myDao.update(this);
   }

基本的屬性:

@Id 標(biāo)志主鍵

@Transient 表示不存儲在數(shù)據(jù)庫中

@NotNull 標(biāo)志這個字段不能是null

@Property 如果定義了這個屬性,那么nameInDb的值就是該列在數(shù)據(jù)表里面,該列的名稱。上面的例子,username的值存儲在數(shù)據(jù)表里面的USERNAME那一列。

主鍵的限制

當(dāng)前,entity必須有一個long或者Long的屬性作為主鍵,但是有時候我們的主鍵不一定是long或者Long型的可能是string呀之類的,這個時候我們就可以定義索引屬性并且注明獨一無二。 如下:

@Index(name = "keyword", unique = true)
private String key;

name用于指明這個索引的列名,unique表示這個指是不可重復(fù)的。

@Unique 用于標(biāo)志列的值的唯一性。

greenDao盡最大的可能的合理的安排每個屬性的默認(rèn)值,所以一般不需要去配置每一個選項。只需要配置你需要的就可以了。

當(dāng)你編寫好的entity之后,只需要點擊Build-> make project就可以自動生成相關(guān)的代碼了。

如果你改變了已經(jīng)存在的entity記得rebuild工程保證舊的entity類被clean掉了。

記住不要隨意修改注明了@Generated的代碼,這樣會導(dǎo)致報錯,

Error:Execution failed for task ':app:greendao'.
> Constructor (see ExampleEntity:21) has been changed after generation.
Please either mark it with @Keep annotation instead of @Generated to keep it untouched,
or use @Generated (without hash) to allow to replace it.

解決這個的辦法有兩個:

  1. 將@Generated注釋改回去,或者將自動生成的代碼刪掉,然后他會自動rebuild在下次build工程的時候。
  2. 將@Generated改成@Keep,這樣greenDao將不會檢查這段代碼,但是這樣可能會導(dǎo)致實體和greenDao其他的契合部分。另外,未來版本的greenDAO可能會在生成的方法中使用不同的代碼。最好是不要修改這個,如果實在要修改,建議編寫測試單元,測試一下確保不會有問題。

@Keep在新版本里面已經(jīng)被淘汰了,如果當(dāng)gradle檢測到有@Keep會將他替換成@Transient!??!注意啦?。?!

實體類建立好了,那么如何操作數(shù)據(jù)庫,通過什么訪問數(shù)據(jù)庫呢,先來介紹一下greenDao的幾個關(guān)鍵的類。

關(guān)鍵的幾個類

DaoMaster

greenDao的入口,持有數(shù)據(jù)庫(SQLiteDatabase)對象 并且 管理Schema的DAO類(不是對象)。持有靜態(tài)的創(chuàng)建于刪除表的方法。內(nèi)部類OpenHelper以及DevOpenHelper實現(xiàn)了SQLiteOpenHelper,創(chuàng)建了數(shù)據(jù)庫模式(Schema)。進(jìn)行數(shù)據(jù)庫連接。

DaoSession

管理特定模式的所有可用的DAO對象,通過getter方法可以獲取到DAO對象。提供了增刪查改實體的方法。

DAOs

全稱Data access Objects,數(shù)據(jù)訪問對象,對于每一個實體類,greenDao生成一個DAO,持有很多持久性的方法,例如 count, loadAll以及insertInTx。

Entities

持久化對象(與數(shù)據(jù)庫對應(yīng)的實體類),對應(yīng)數(shù)據(jù)庫里面的一行。

在用數(shù)據(jù)庫之前首先需要初始化數(shù)據(jù)庫,一般我們在Application里面進(jìn)行數(shù)據(jù)庫的數(shù)據(jù)化,并且只初始化一次。

// do this once, for example in your Application class
helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
db = helper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();

然后要操作對應(yīng)的對象的時候只需要獲取到對應(yīng)的Dao對象即可:

// do this in your activities/fragments to get hold of a DAO
noteDao = daoSession.getNoteDao();

Session

DaoSession是greenDao重要的接口之一,提供了基本的實體類操作,Daos提供了更多的完整的操作。
獲取Session

daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();

請注意,數(shù)據(jù)庫連接屬于DaoMaster,因此多個會話引用相同的數(shù)據(jù)庫連接。 因此,可以很快創(chuàng)建新的會話。 但是,每個會話都會分配內(nèi)存,通常是實體的會話“緩存”。

Identity scope and session “cache”

如果有兩個查詢返回相同的數(shù)據(jù)庫對象,那么您使用的Java對象有多少個:一個還是兩個?它完全取決于身份范圍。

greenDAO中的默認(rèn)值(行為是可配置的)是多個查詢返回對相同Java對象的引用。例如,從ID為42的USER表中加載一個User對象為這兩個查詢返回相同的Java對象。

這個副作用是某種實體“緩存”。如果一個實體對象仍然在內(nèi)存中(greenDAO在這里使用弱引用),則該實體不會再構(gòu)造。另外,greenDAO不執(zhí)行數(shù)據(jù)庫查詢來更新實體值。相反,對象會從會話緩存中“立即”返回,這會比一個或兩個數(shù)量級更快。

清除identity scope

清除整個session,沒有緩存對象返回

daoSession.clear(); 

清除單個Dao的identity scope ,這樣某個dao不會有緩存對象返回

noteDao = daoSession.getNoteDao();
noteDao.detachAll();

Queries

在GreenDao,你可以自己寫原生的查詢語句,也可以通過QueryBuilderAPI來查詢。

Query用于查詢的類

  • QueryBuilder

SQL的語法錯誤只有在run time的時候才會提示,但是用greenDaoQueryBuilder可以在編譯的時候就檢測到錯誤。

查詢范例:

List<User> joes = userDao.queryBuilder()
  .where(Properties.FirstName.eq("Joe"))
  .orderAsc(Properties.LastName)
  .list();

用對應(yīng)的Dao對對應(yīng)的表進(jìn)行查詢操作,調(diào)用qureyBuilder方法,where是查詢條件,可以有多個查詢條件,用逗號分隔開來,如下:

List<User> joes = userDao.queryBuilder()
  .where(Properties.FirstName.eq("Joe"), Properties.AGE.eq("10")
  .orderAsc(Properties.LastName)
  .list();

上面語句查詢lastname是joe的并且年齡是10歲的人。

復(fù)雜的不是and連接的查詢語句可以如下查詢:

多個條件查詢:

QueryBuilder<User> qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List<User> youngJoes = qb.list();

上面語句應(yīng)該如下解釋

 First name is "Joe" AND (year of birth is greater than 1970 OR (year of birth is 1970 AND month of birth is equal to or greater than 10))

即找出first name是joe的然后出生于1970年10以后的。

order

排序,我們可以對查詢的結(jié)果進(jìn)行排序。

orderAsc(依據(jù)的屬性名稱,可以有多個屬性),正序 orderDesc 倒序

// order by last name
queryBuilder.orderAsc(Properties.LastName);
 
// in reverse
queryBuilder.orderDesc(Properties.LastName);
 
// order by last name and year of birth
queryBuilder.orderAsc(Properties.LastName).orderDesc(Properties.YearOfBirth);

greenDAO使用的默認(rèn)排序規(guī)則是COLLATE NOCASE,盡管它可以使用stringOrderCollation()進(jìn)行定制。 有關(guān)影響結(jié)果順序的其他方法,請參見QueryBuilder類文檔。

limit

當(dāng)你根據(jù)條件查詢,返回N條數(shù)據(jù)的時候,但是你只想要里面的前十個的時候,這個時候用limit可以限制獲取 n條數(shù)據(jù),不用for循環(huán)cursor。

limit

limit(int)限制查詢返回的條數(shù)。

需求千變?nèi)f化的,有時候你需要的不是前面的n條,而是從位置m開始的n條數(shù)據(jù),這個時候就可以用offset 設(shè)置數(shù)據(jù)返回的偏移值。

offset(int)

設(shè)置返回數(shù)據(jù)的起始偏移值,得到offset開始的n條數(shù)據(jù)。必須要結(jié)合limit(int n)來使用

queryBuilder().where(Properties.YearOfBirth.gt(2001)).offset(3).limit(10)

上面例子是取出出生年份大于2001年的第3個開始的十個人。

查詢條件總結(jié)

  • eq : Properties.YearOfBirth.eq(2001): 等于
  • notEq : 不等于
  • like:模糊查詢 記住模糊查詢,string要用夾在%key%中間。
xxDao.queryBuilder().where(Properties.FirstName.like("%doris%")).list();

查詢FristName包含doris的人。

  • BETWEEN ... AND ... ...和...之間。
  • IN(..., ..., ...) 在給出的value的范圍內(nèi)的符合項
  • gt 大于
  • ge 大于等于
  • lt 小于
  • le 小于等于
  • isNull 不是空的

查詢有懶查詢,也叫延遲查詢吧,我覺得,就會你先執(zhí)行了查詢語句但是呢只有在你用的時候才會加載到內(nèi)存,就類似于懶加載。

  • list() 不是懶加載,正常查詢,查詢結(jié)果立馬加載到內(nèi)存。
  • listLazy() 實體按需加載到內(nèi)存中。 一旦列表中的元素第一次被訪問,它將被加載并緩存以供將來使用。 必須關(guān)閉。
  • listLazyUncached() 一個“虛擬”實體列表:對列表元素的任何訪問都會導(dǎo)致從數(shù)據(jù)庫加載其數(shù)據(jù)。 必須關(guān)閉。
  • listIterator() 讓我們通過按需加載數(shù)據(jù)(懶惰地)來遍歷結(jié)果。 數(shù)據(jù)沒有被緩存。 必須關(guān)閉。

greenDao還支持多線程查詢以及重復(fù)使用Query對象,這個我還沒用到,用到給大家再深入講解一下哈!

原始查詢

方法1:

Query<User> query = userDao.queryBuilder().where(
  new StringCondition("_ID IN " +
    "(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)")
).build();

方法2:
queryRawqueryRawCreate

Query<User> query = userDao.queryRawCreate(
  ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin"
);

debug查詢

QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;

設(shè)置這兩個屬性就可以看到log、

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容