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

来源:http://www.cnblogs.com/dsxniubility/archive/2016/12/29/6204169.html
-Advertisement-
Play Games

大致分為以下幾個方面: 一些查詢指令整理 使用SQL語句進行特殊查詢 檢測表欄位是否存在 資料庫升級 資料庫表欄位賦初始值 一、查詢指令整理 1.鏈式執行的指令 一般的查詢語句會在中間xxx的位置加上各種判斷和過濾的方法指令,除了最後的終結指令list()或unique()返回的是集合或業務對象,其 ...


大致分為以下幾個方面:

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

一、查詢指令整理

1.鏈式執行的指令

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

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

“whereOr” where語句裡面寫的條件都是用“且”連接,whereOr里的語句使用“或”連接

“distinct”  直接過濾掉重負欄位

“limit”  分頁n個一頁,一般和offset結合使用

“offset” 忽略查詢出的前n條結果

“orderAsc” 以欄位升序排序

“orderDesc”以欄位降序

“preferLocalizedStringOrder” 本地化字元串排序

“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” 不為空 

二、使用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();
            }
        }

下麵可以一次性的取出三個所需欄位進行使用,需要先得到欄位對應索引,然後再對著索引取值。

三、檢測表欄位是否存在

        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。

四、資料庫升級

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

然後重寫父類的這個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);
            }

五、資料庫表欄位賦初始值

有些欄位的初始值如果你不希望是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都會先自動生成一下,這種情況每次都會覆蓋。

 

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現在的css3真是強大,之前很多動畫都是用jq來實現,但是css3製作的動畫要比jq實現起來簡單很多,今天呢,我自己也寫了一個css旋轉動畫和大家分享。效果如下麵的圖片 思路:1.製作之前呢,我們先來整理一下思路,這個圓軸軌跡上一共有八個圓。 仔細看的話,你會發現一個規律,那就是一個月是360度的, ...
  • 前言 昨日,我請了一天假去考科目三,結果第一把掛在了沒完全關閉燈光上,第二把掛在轉彎時沒有觀察後方車輛,當聽到師傅一句“下去”的時候,我那是悲痛的面紅耳赤,這讓我很鬱悶,晚上也就不想回去上班了,回家後仍然有點低沉,在這種情況下,不寫點毒雞湯,好像已經不能好好的調節心情了,看看時間年底了,便寫寫今年的 ...
  • 學習 Activity 生命周期時希望通過 Dialog 主題測試 onPause() 和 onStop() 的區別。 點擊按鈕跳轉 Activity 時報錯: 找到最有用的一句話,說明所使用的 theme 和當前 Activity 不匹配。 AndroidManifest.xml 中 activi ...
  • 以下內容為原創,歡迎轉載,轉載請註明 來自天天博客: 使用Dagger 2進行依賴註入 Producers 原文: 本文是在Android中使用Dagger 2框架進行依賴註入的系列文章中的一部分。今天我們將探索下Dagger Producers 使用Java實現非同步依賴註入的Dagger2的一個擴 ...
  • 12.29日,小程式服務範圍做了重大更新,增對富媒體和工具類型的小程式,增加了很多細分領域 富媒體:增加資訊,FM電臺,有聲讀物等,媒體平臺可上小程式了 工具:信息查詢,網路代理,健康,企業管理等 ,更多查詢服務可以上線,企業辦公也可上了 商業服務:新增法律服務,不需要資格證書 ,線上法律咨詢可以上 ...
  • 由[OpenDigg](http://www.opendigg.com/) 出品的iOS開源項目周報第三期來啦。我們的iOS開源周報集合了OpenDigg一周來新收錄的優質的iOS開發方面的開源項目,方便iOS開發人員便捷的找到自己需要的項目工具等。 ...
  • 摘要:我們來瞭解一下MVVM模式與Databinding ,MVVM是一種模式,Databinding 是一種框架。DataBinding是一個實現數據和UI綁定的框架。而ViewModel和View可以通過DataBinding來實現單向綁定和雙向綁定,這套UI和數據之間的動態監聽和動態更新的框架 ...
  • 提到FlexboxLayout大家估計有點模糊,它是谷歌最近開源的一個android排版庫,它的前身Flexbox是2009年W3C提出了一種新的佈局,可以簡便、完整、響應式的實現頁面佈局,Flexbox 是屬於web前端領域CSS的一種佈局方案。 首先:我們看一下它的屬性。 flexDirecti ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...