安卓GreenDao框架一些進階用法整理

大體分爲如下幾個方面:java

  • 一些查詢指令整理
  • 使用SQL語句進行特殊查詢
  • 檢測表字段是否存在
  • 數據庫升級
  • 數據庫表字段賦初始值

1、查詢指令整理

1.鏈式執行的指令

        return mDaoSession.getUserDao().queryBuilder().
                XXX.
                XXX.
                XXX.
                list();

通常的查詢語句會在中間xxx的位置加上各類判斷和過濾的方法指令,除了最後的終結指令list()或unique()返回的是集合或業務對象,其餘的都是返回QueryBuilder對象,大多數狀況下XXX的位置都是填上where語句,還有一些其餘和sql關聯的語句便於使用。sql

「whereOr」 where語句裏面寫的條件都是用「且」鏈接,whereOr裏的語句使用「或」鏈接數據庫

「distinct」  直接過濾掉重負字段api

「limit」  分頁n個一頁,通常和offset結合使用session

「offset」 忽略查詢出的前n條結果ide

「orderAsc」 以字段升序排序gradle

「orderDesc」以字段降序ui

「preferLocalizedStringOrder」 本地化字符串排序spa

「orderCustom」 自定義排序 裏面須要傳兩個參數: 一個屬性 和對應的排序方案 ASC 或是 DESC 版本控制

「orderRaw」  也是自定義排序, 把字段和 排序方案 寫在一個字符串傳入

「stringOrderCollation」 也是自定義排序 能夠合併多個升降排序方案 以日期升序 且 價格降序

 

2.條件裏的指令

        return mDaoSession.getUserDao().queryBuilder().
                where(UserDao.Properties.UserId.in(userIdList), UserDao.Properties.UserAge.eq(19)).
                list();

一個簡單的where語句大概是這樣,在where的括號裏面能夠並列的寫不少條件,其中所有以「且」 來鏈接。除了上面的「in」和「eq」還有不少其餘判斷條件

「notEq」 和eq相反,別傻傻在再去外面敲「!」取反

「notIn」 同上

「or」 或者

「like」 就是sql語句的LIKE  "%"+string+"%"

「between」 也就是BETWEEN ? AND ?  能夠取兩個值的區間 (可是這條語句要慎用,不一樣的數據庫不同,有的是A<條件<B,有的是A<=條件<=B)

「gt」 至關於 > 

「ge」至關於 >=

「lt」 至關於 <

「le」至關於  <=

「isNull」 爲空

「notIsNull」 不爲空 

2、使用SQL語句進行特殊查詢

通常遇到普通的增刪改查操做沒法輕易實現的功能,會使用這種rawQuery的方式。 我常常遇到的也就是兩種場景:

 

1.使用SELECT DISTINCT

經常使用與一對多關係,假設圖書館如今有個「用戶存書表」 有的用戶有20本書,表裏就會有20條他的數據,每條對應一本不一樣的書。

這時假設有個需求,查出這個表中,全部的用戶名字,不準重複。 這時候用普通的查詢指令就會很是麻煩了,須要使用SELECT DISTINCT指令查出某列名全部不重複的條目。

        String queryString =
                "SELECT DISTINCT " + UserBookDao.Properties.UserName.columnName + " FROM " + UserBookDao.TABLENAME
                        + " ORDER BY "
                        + UserBookDao.Properties.CreatedTime
                        + " DESC "
                        + " LIMIT "
                        + page * LIMIT_NUM
                        + " , "
                        + LIMIT_NUM;

        ArrayList<String> result = new ArrayList<>();
        Cursor c = mDaoSession.getDatabase().rawQuery(queryString,new String[]{});
        try {
            if (c != null) {
                if (c.moveToFirst()) {
                    do {
                        result.add(c.getString(0));
                    } while (c.moveToNext());
                }
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }

大概代碼的畫風就是這個樣子,先拼接出一個符合sql語法的字符串,上面也隨機加了一寫其餘的操做指令字段排序和分頁,使得查詢指令看上去更加完整,而後使用遊標來接收上面的查詢結果。

可能大多數查詢的時候會帶上一些參數,好比where XX = XX 的過濾條件,假設有個需求須要在以前的查詢用戶需求上加上對出版社和圖書價格的限制,則查詢方式以下

        String queryString =
                "SELECT DISTINCT " + UserBookDao.Properties.UserName.columnName + " FROM " + UserBookDao.TABLENAME   // 董鉑然博客園
                        + " WHERE "
                        + UserBookDao.Properties.Publisher.columnName + " = ?"
                        + " AND "
                        + UserBookDao.Properties.Price.columnName + " > ?"
                        + " ORDER BY "
                        + UserBookDao.Properties.CreatedTime
                        + " DESC ";

        ArrayList<String> result = new ArrayList<>();
        Cursor c = mDaoSession.getDatabase().rawQuery(queryString, new String[]{"某出版社"),
                String.valueOf(100.00)});
        try {
            if (c != null) {
                if (c.moveToFirst()) {
                    do {
                        result.add(c.getString(0));
                    } while (c.moveToNext());
                }
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }

帶上參數的查詢字符串須要在上面使用問號佔位,而後在下面用rawQuery帶參數的api裏填上相關的入參。

 

2. SELECT同時查詢多個字段

 仍是用這個查書的例子,假設一下要查「書名」、「出版社」、「價格」 三個字段

        String queryString = "SELECT "
                + UserBookDao.TABLENAME + "." + UserBookDao.Properties.BookName.columnName + ","
                + UserBookDao.TABLENAME + "." + UserBookDao.Properties.Publisher.columnName + ","
                + UserBookDao.TABLENAME + "." + UserBookDao.Properties.Price.columnName + " "
                + "FROM "
                + UserBookDao.TABLENAME + " "
                + "WHERE"
                + UserBookDao.Properties.Price + " > 100.00 ";

        Cursor cursor = null;
        try {
            cursor = session.getDatabase().rawQuery(queryString,new String[]{});
            if (cursor == null) {
                return payMap;
            }
            // 取出三個字段分別對應的索引,下面再對着索引去取值
            int nameIndex = cursor.getColumnIndex(UserBookDao.Properties.BookName.columnName);
            int publisherIndex = cursor.getColumnIndex(UserBookDao.Properties.Publisher.columnName);
            int priceIndex = cursor.getColumnIndex(UserBookDao.Properties.Price.columnName);

            if (nameIndex != -1 && publisherIndex != -1 && priceIndex != -1) {
                while (cursor.moveToNext()) {
                    String name = cursor.getString(nameIndex);
                    String publisher = cursor.getString(publisherIndex);
                    Double price = cursor.getDouble(priceIndex);
                    // 這裏取到三個字段 本身是存模型仍是字典 本身處理。
                }
            }
        } finally {
            if (null != cursor) {
                cursor.close();
            }
        }

下面能夠一次性的取出三個所需字段進行使用,須要先獲得字段對應索引,而後再對着索引取值。

3、檢測表字段是否存在

        private boolean hasColumn(SQLiteDatabase db, String tableName, String column) {
            if (TextUtils.isEmpty(tableName) || TextUtils.isEmpty(column)) {
                return false;
            }
            Cursor cursor = null;
            try {
                cursor = db.query(tableName, null, null, null, null, null, null);
                if (null != cursor && cursor.getColumnIndex(column) != -1) {
                    return true;
                }
            } finally {
                if (null != cursor) {
                    cursor.close();
                }
            }
            return false;
        }

和上面取遊標的方式相似,取出的列索引值若是不是-1,則表明可以取到這個字段返回true,不然和入參非法一塊兒返回fasle。

4、數據庫升級

這邊會調用上面判斷列名是否已經存在的方法。

而後重寫父類的這個onUpgrade方法

    private static class DemoOpenHelper extends DaoMaster.OpenHelper {

        public DemoOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
            super(context, name, factory);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // 數據庫的版本控制 能夠隨着版本疊加不斷增長差值
            if (oldVersion < 2) {
                if (!hasColumn(db, UserBookDao.TABLENAME, UserBookDao.Properties.Author.columnName)) {
                    String sql = "alter table " + UserBookDao.TABLENAME +
                            " add COLUMN " + UserBookDao.Properties.Author.columnName + " TEXT";
                    db.execSQL(sql);
                }
                if (!hasColumn(db, UserBookDao.TABLENAME, UserBookDao.Properties.Type.columnName)) {
                    String sql = "alter table " + UserBookDao.TABLENAME +
                            " add COLUMN " + UserBookDao.Properties.Type.columnName + " INTEGER";
                    db.execSQL(sql);
                }
            }
        }
    }

除了上面的修改表,若是改動太多或是換了代表,還能夠直接刪了重建(這麼作的話以前的數據也就刪了)

            if (oldVersion < 3) {
                UserDao.dropTable(new StandardDatabase(db),true);
                UserStudentDao.createTable(new StandardDatabase(db),true);
            }

5、數據庫表字段賦初始值

有些字段的初始值若是你不但願是0,或是空字符串,能夠賦初始值。如今的賦值初始值就分爲兩種狀況了

 

1.建表時附初始值

在3.0之前的版本 仍是要寫一個module,裏面寫相似代碼來建表的

    private static void addUser(Schema schema) {
        Entity user = schema.addEntity("User");
        user.addIdProperty();
        user.addStringProperty("name").notNull().defValue("\"jack\"");
        user.addStringProperty("address");
        user.addStringProperty("teacher");
        user.addIntProperty("age").primJavaType().defValue("17");
    }

在3.0以後推行用註解和直接寫Entity的寫法,因此能夠直接在Entity的類裏指定

@Entity
public class Student {
    @Id(autoincrement = true)
    private long id; //主鍵
    private String name;
    private String schoolTime = "09-01"; //開學時間默認都是9月1日
    private int age = 19; // 剛上大學的默認都是19歲
    // 下面生成的getter 和setter省略 。。。
}

 

2.數據庫升級時給升級字段賦初始值

上面說的的數據庫升級,是須要寫一條alter table的sql語句,能夠直接拼接到這一行後面

            // 上面判斷該列名是否存在
            // ...
            String sql = "alter table " + UserBookDao.TABLENAME +
                    " add COLUMN " + UserBookDao.Properties.Type.columnName + " INTEGER" + " NOT NULL DEFAULT(-1) "; // 直接拼接在語句最後 董鉑然博客園
            db.execSQL(sql);
            // ...

注:之前聽過一種說法是直接在UserDao這種生成的類裏直接在生成的建立語句後面拼接DEFAULT,這裏很是反對, 首先人家類名明確代表 // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.  而且有些人的代碼可能設置的是手動生成,但咱們的項目就在gradle裏設置了每次build都會先自動生成一下,這種狀況每次都會覆蓋。

 

開發中一些整理,歡迎討論。

相關文章
相關標籤/搜索