1. 程式人生 > >GreenDao 3.X之基本使用

GreenDao 3.X之基本使用

sof list() nts 一行 details 選擇 pri all cond

在 GreenDao 3.X之註解已經了解到GreenDao 3.0的改動及註解。對於數據庫的操作,無異於增刪改查等四個操作。下面我們將了解GreenDao 3.X如何使用?

AbstractDao

所有的自動生成的XXDao都是繼承於AbstractDao,此類中基本上封裝了所有的增刪改操作,包括數據庫的事務操作。常用的API如下:

    void     attachEntity(T entity):
    
    long     count():獲取數據庫中數據的數量
    
    // 數據刪除相關
    void     delete(T entity):從數據庫中刪除給定的實體
    
void deleteAll() :刪除數據庫中全部數據 void deleteByKey(K key):從數據庫中刪除給定Key所對應的實體 void deleteByKeyInTx(java.lang.Iterable<K> keys):使用事務操作刪除數據庫中給定的所有key所對應的實體 void deleteByKeyInTx(K... keys):使用事務操作刪除數據庫中給定的所有key所對應的實體 void deleteInTx(java.lang.Iterable<T> entities):使用事務操作刪除數據庫中給定實體集合中的實體
void deleteInTx(T... entities):使用事務操作刪除數據庫中給定的實體 // 數據插入相關 long insert(T entity):將給定的實體插入數據庫 void insertInTx(java.lang.Iterable<T> entities):使用事務操作,將給定的實體集合插入數據庫 void insertInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey):使用事務操作,將給定的實體集合插入數據庫, 並設置是否設定主鍵
void insertInTx(T... entities):將給定的實體插入數據庫 long insertOrReplace(T entity):將給定的實體插入數據庫,若此實體類存在,則覆蓋 void insertOrReplaceInTx(java.lang.Iterable<T> entities):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則覆蓋 void insertOrReplaceInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則覆蓋 並設置是否設定主鍵 void insertOrReplaceInTx(T... entities):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則覆蓋 long insertWithoutSettingPk(T entity):將給定的實體插入數據庫,但不設定主鍵 // 新增數據插入相關API void save(T entity):將給定的實體插入數據庫,若此實體類存在,則更新 void saveInTx(java.lang.Iterable<T> entities):將給定的實體插入數據庫,若此實體類存在,則更新 void saveInTx(T... entities):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則更新 // 加載相關 T load(K key):加載給定主鍵的實體 java.util.List<T> loadAll():加載數據庫中所有的實體 protected java.util.List<T> loadAllAndCloseCursor(android.database.Cursor cursor) :從cursor中讀取、返回實體的列表,並關閉該cursor protected java.util.List<T> loadAllFromCursor(android.database.Cursor cursor):從cursor中讀取、返回實體的列表 T loadByRowId(long rowId) :加載某一行並返回該行的實體 protected T loadUnique(android.database.Cursor cursor) :從cursor中讀取、返回唯一實體 protected T loadUniqueAndCloseCursor(android.database.Cursor cursor) :從cursor中讀取、返回唯一實體,並關閉該cursor //更新數據 void update(T entity) :更新給定的實體 protected void updateInsideSynchronized(T entity, DatabaseStatement stmt, boolean lock) protected void updateInsideSynchronized(T entity, android.database.sqlite.SQLiteStatement stmt, boolean lock) void updateInTx(java.lang.Iterable<T> entities) :使用事務操作,更新給定的實體 void updateInTx(T... entities):使用事務操作,更新給定的實體

QueryBuilder、Query

基本查詢

GreenDao中,使用QueryBuilder自定義查詢實體,而不是再寫繁瑣的SQL語句,避免了SQL語句的出錯率。大家都知道寫SQL語句時,非常容易出錯,出錯後又十分的難查。QueryBuilder真是幫忙解決了一個大麻煩。具體該如何使用呢?

    List joes = userDao.queryBuilder()
                       // 查詢的條件
                       .where(Properties.FirstName.eq("Joe"))
                       // 返回實體集合升序排列
                       .orderAsc(Properties.LastName)
                       .list();
    QueryBuilder 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 youngJoes = qb.list();    </span>

上面是官方給出的兩個列子,不僅滿足了查詢語句的易寫,同時使用了流式寫法,提高了代碼的可閱讀性。

Limit、Offset、Pagination

在實際開發過程中,大家肯定碰到這樣的問題,當數據過多在一頁顯示不出來的時候,要麽選擇前面十條顯示,要麽分頁顯示,但是數據總是獲取全部的。其實,剛接觸GreenDao的時候,也是這麽幹,獲取全部的實體集合,然後再根據實際情況截取。看了API以後,豁然開朗,大神們已經幫我們解決了這件事。此時不得不說,QueryBuilder
中的Limit(限制)、Offset(偏移),limit(int)和offset(int)協同設置,可以完美解決分頁顯示。

        limit(int):限制查詢返回結果的數目
        offset(int):設置查詢結果的偏移量,此查詢需與limit(int)結合使用,而不能夠脫離limit(int)單獨使用

Query

當執行多次查詢時,實際是QueryBuilder多次調用Query類。如果執行多次相同的查詢,應使用QueryBuilder的build()方法來創建Query,而不是直接使用Query類。如果查詢返回的結果是唯一性的,可以使用操作符方法,如果不希望此唯一性不返回 null,此時可調用uniqOrThrow()方法。如果查詢返回的結果是多個,可以使返回的結果是一個集合,有如下方法:

list():所有實體加載至內存,結果通常是一個ArrayList  
listLazy():實體在需要時,加載至內存,表中的第一個元素被第一次訪問時會被緩存,下次訪問時,使用緩存  
listLazyUncached():任何對列表實體的訪問懂事從數據庫中加載  
listIterator():以按需加載的方式來遍歷結果,數據沒有被緩存  

一旦使用QueryBuilder創建了一個query,那麽這個Query對象就可以就可以被復用來執行查詢顯然這種方式逼重新創建一次Query效率要高。
具體來說:

如果Query的參數沒有變更,你只需要再次調用List/unuque方法即可  
如果參數發生了變化,那麽就需要通過setParameter方法來處理每一個發生改變的參數  

舉例:

Query query = userDao.queryBuilder().where(Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)).build();  
List joesOf1970 = query.list();  

現在復用該Query對象:

query.setParameter(0, "Maria");  
query.setParameter(1, 1977);  
List mariasOf1977 = query.list();  

由此可見,Query在執行一次build之後會將查詢結果進行緩存,方便下次繼續使用。

執行原生SQL語句

兩種方法:

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

如果這裏的QueryBuilder沒有提供你想要的特性,可以使用原始的queryRaw或queryRawCreate方法。

Query query = userDao.queryRawCreate(  ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin"

註:寫SQL語句時推薦定義常量來表示表名或者表項,這樣可以防止出錯,因為編譯器會檢查

基本使用

創建實體類

@Entity(generateConstructors = false)
public class Student {
    @Id
    private Long id;
    private String name;
    private int age;

    public Student() {
    }

    @Keep
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


    public Student(Long id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    @Keep
    public Long getId() {
        return id;
    }

    @Keep
    public void setId(Long id) {
        this.id = id;
    }

    @Keep
    public String getName() {
        return name;
    }

    @Keep
    public void setName(String name) {
        this.name = name;
    }

    @Keep
    public int getAge() {
        return age;
    }

    @Keep
    public void setAge(int age) {
        this.age = age;
    }

    @Keep
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;

        Student student = (Student) o;

        return name.equals(student.name);

    }

    @Keep
    @Override
    public int hashCode() {
        return (int) (id ^ (id >>> 32));
    }

    @Keep
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name=‘" + name + \‘ +
                ", age=" + age +
                };
    }
}

創建完實體類後,Rebuild Project生成DaoMaster、DaoSession。DaoMaster、DaoSession位於在Gradle設置的目錄及文件夾裏。

技術分享

技術分享

創建Database管理類

public class DbManager {  
  
    // 是否加密  
    public static final boolean ENCRYPTED = true;  
  
    private static final String DB_NAME = "tea.db";  
    private static DbManager mDbManager;  
    private static DaoMaster.DevOpenHelper mDevOpenHelper;  
    private static DaoMaster mDaoMaster;  
    private static DaoSession mDaoSession;  
  
    private Context mContext;  
  
    private DbManager(Context context) {  
        this.mContext = context;  
        // 初始化數據庫信息  
        mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);  
        getDaoMaster(context);  
        getDaoSession(context);  
    }  
  
    public static DbManager getInstance(Context context) {  
        if (null == mDbManager) {  
            synchronized (DbManager.class) {  
                if (null == mDbManager) {  
                    mDbManager = new DbManager(context);  
                }  
            }  
        }  
        return mDbManager;  
    }  
  
    /** 
     * @desc 獲取可讀數據庫 
     * @autor Tiany 
     * @time 2016/8/13 
     **/  
    public static SQLiteDatabase getReadableDatabase(Context context) {  
        if (null == mDevOpenHelper) {  
            getInstance(context);  
        }  
        return mDevOpenHelper.getReadableDatabase();  
    }  
  
    /** 
     * @desc 獲取可寫數據庫 
     * @autor Tiany 
     * @time 2016/8/13 
     **/  
    public static SQLiteDatabase getWritableDatabase(Context context) {  
        if (null == mDevOpenHelper) {  
            getInstance(context);  
        }  
        return mDevOpenHelper.getWritableDatabase();  
    }  
  
    /** 
     * @desc 獲取DaoMaster 
     * @autor Tiany 
     * @time 2016/8/13 
     **/  
    public static DaoMaster getDaoMaster(Context context) {  
        if (null == mDaoMaster) {  
            synchronized (DbManager.class) {  
                if (null == mDaoMaster) {  
                    mDaoMaster = new DaoMaster(getWritableDatabase(context));  
                }  
            }  
        }  
        return mDaoMaster;  
    }  
  
    /** 
     * @desc 獲取DaoSession 
     * @autor Tiany 
     * @time 2016/8/13 
     **/  
    public static DaoSession getDaoSession(Context context) {  
        if (null == mDaoSession) {  
            synchronized (DbManager.class) {  
                mDaoSession = getDaoMaster(context).newSession();  
            }  
        }  
  
        return mDaoSession;  
    }  
}  
數據庫操作類
[java] view plain copy
public class StudentDaoOpe {  
  
    /** 
     * @desc 添加數據至數據庫 
     * @autor Tiany 
     * @time 2016/8/13 
     **/  
    public static void insertData(Context context, Student stu) {  
  
        DbManager.getDaoSession(context).getStudentDao().insert(stu);  
    }  
  
    /** 
     * @desc 將數據實體通過事務添加至數據庫 
     * @autor Tiany 
     * @time 2016/8/13 
     **/  
    public static void insertData(Context context, List<Student> list) {  
        if (null == list || list.size() <= 0) {  
            return;  
        }  
        DbManager.getDaoSession(context).getStudentDao().insertInTx(list);  
    }  
  
    /** 
     * @desc 添加數據至數據庫,如果存在,將原來的數據覆蓋 
     * @autor Tiany 
     * @time 2016/8/15 
     **/  
    public static void saveData(Context context, Student student) {  
        DbManager.getDaoSession(context).getStudentDao().save(student);  
    }  
  
    /** 
     * @desc 查詢所有數據 
     * @autor Tiany 
     * @time 2016/8/15 
     **/  
    public static List<Student> queryAll(Context context) {  
        QueryBuilder<Student> builder = DbManager.getDaoSession(context).getStudentDao().queryBuilder();  
  
        return builder.build().list();  
    }  
}  


到此為止,數據庫的基本操作已完成,根據實際需求笤俑數據庫操作類相應的操作即可。

現流行RxJava異步及流式開發,GreenDao已將RxJava集成,具體的使用見

參考文檔

1、官方文檔

2.、GreenDAO 3.0 初次使用

GreenDao 3.X之基本使用