android sqlite orm

來源:互聯網
上載者:User

標籤:

要過年了,最近比較閑整理下以前的代碼。

14年寫的sqlite orm庫,當時為了儘快熟悉android資料庫操作,所以自己動手寫了這個庫。然後用這個庫開發了幾個項目發現用的還是比較順手的,於是就寫篇部落格記錄下吧。

我理解的orm的核心思想就是以對象為單位進行增刪改查。

app開發給欄位命名是很麻煩的一件事,特別是當頁面有很多控制項的時候,要兼顧介面開發人員命名風格和頁面快速辨認需求,如果orm再要求欄位名還要考慮到資料表欄位命名的問題就太麻煩了,於是我使用了反射來實現模型欄位和資料表欄位的對應。

public class SQLiteUtil {    private SQLiteDatabase db;    private Context context;    /**     * @param dbName     * @param context     */    public SQLiteUtil(String dbName, Context context) {        this.context = context;        //開啟或建立資料庫        db = this.context.openOrCreateDatabase(dbName, Context.MODE_PRIVATE, null);    }    /**     * 建表語句,如果表不存在則建表     *     * @param table 表結構,樣本 tableName(field1 text primary key, field2 integer)     */    public void createTable(String table) {        String cts = "create table if not exists " + table + "; ";//建表語句        db.execSQL(cts);    }    /**     * 刪除表     *     * @param table 表名     */    public void deleteTable(String table) {        String sql = "DROP TABLE IF EXISTS " + table;        db.execSQL(sql);    }    /**     * 執行sql命令     *     * @param sql     */    public void execSql(String sql) {        db.execSQL(sql);    }    /**     * 增加一條新的資料     */    public <T> void insert(String tableName, T data, Class<T> clazz) {        String sql = "insert into " + tableName + " ";        String fields = "( ";        String value = " VALUES( ";        for (Field f : clazz.getDeclaredFields()) {            f.setAccessible(true);            if (null != f.getAnnotation(SqlField.class)) {                SqlField ta = f.getAnnotation(SqlField.class);                fields += ta.field() + ",";                try {                    if (f.getType().getSimpleName().equals("int")) {                        value += f.getInt(data) + ",";                    } else if (f.getType().getSimpleName().equals("String")) {                        value += "‘" + f.get(data).toString() + "‘,";                    }                } catch (IllegalAccessException e) {                    e.printStackTrace();                }            }        }        fields = fields.substring(0, fields.length() - 1) + ") ";        value = value.substring(0, value.length() - 1) + ") ";        sql = sql + fields + value;        StaticMethod.debugEMSG(sql);        db.execSQL(sql);    }    /**     * 修改資料     */    public <T> void update(String tableName, String where, T data, Class<T> clazz) {        String sql = "UPDATE " + tableName + " SET ";        String set = "";        for (Field f : clazz.getDeclaredFields()) {            f.setAccessible(true);            if (null != f.getAnnotation(SqlField.class)) {                SqlField ta = f.getAnnotation(SqlField.class);                try {                    if (f.getType().getSimpleName().equals("int")) {                        set += " " + ta.field() + " = " + f.getInt(data) + ",";                    } else if (f.getType().getSimpleName().equals("String")) {                        if (f.get(data).toString() != null)                            set += " " + ta.field() + " = ‘" + f.get(data).toString() + "‘,";                    }                } catch (IllegalAccessException e) {                    e.printStackTrace();                }            }        }        set = set.substring(0, set.length() - 1);        sql = sql + set + where;        db.execSQL(sql);    }    /**     * 查詢方法,返回對應的數組     *     * @param sql     * @param <T> 泛型對象,必須提供一個空白建構函式     * @return     */    public <T> List<T> query(String sql, Class<T> clazz) {        List<T> result = new ArrayList<T>();        Cursor c = db.rawQuery(sql, null);        try {            while (c.moveToNext()) {                T temp = (T) Class.forName(clazz.getName()).newInstance();                for (Field f : clazz.getDeclaredFields()) {                    f.setAccessible(true);                    if (null != f.getAnnotation(SqlField.class)) {                        SqlField ta = f.getAnnotation(SqlField.class);                        if (f.getType().getSimpleName().equals("int")) {                            f.set(temp, c.getInt(c.getColumnIndex(ta.field())));                        } else if (f.getType().getSimpleName().equals("String")) {                            f.set(temp, c.getString(c.getColumnIndex(ta.field())));                        }                    }                }                result.add(temp);            }        } catch (Exception e) {            e.printStackTrace();        } finally {            c.close();        }        return result;    }    /**     * 查     *     * @param sql       查詢語句     * @param fieldName 要返回的欄位名稱     * @return 返回字串內容     */    public List<String> query(String sql, String fieldName) {        Cursor c = db.rawQuery(sql, null);        List<String> result = new ArrayList<String>();        while (c.moveToNext()) {            result.add(c.getString(c.getColumnIndex(fieldName)));        }        c.close();        return result;    }}

  沒有刪除方法,實際開發中刪除操作都是業務比較複雜的,我都是在封裝好sql語句後直接調用execSql(sqlString)來實現刪除。

  查詢有1個重載,是因為在開發時有比較多的業務情境只需要儲存和讀取一張表中的某個欄位,為了這個欄位實現一個model太麻煩,所以有了重載方法。

  增查改中都使用了反射,sql語句也沒有最佳化。因為從實際開發角度來看,以app的資料庫裡的資料量級,做不做最佳化效果區別不大,所以可以放心食用。

  貼一下Annotation的代碼

@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface SqlField {    String field();}

  annotation使用例子

   @SqlField( field = "field1")    public String key;    @SqlField( field = "field2")    public String json;

  例如,執行查詢的時候,orm會從資料表中取出field1的值,並賦值給key欄位。取出field2欄位的值並賦值給json欄位。

 

  最後再來說一下我的使用經驗,一般我會根據業務需求對orm再次封裝。例如做緩衝時,記憶體緩衝,SharedPreferences緩衝和sqlite緩衝以及檔案快取,都要根據業務來配置,其中sqlite緩衝就可以通過二次封裝這個orm來實現。

     下面是我的sqlite緩衝實現代碼

public class SqliteCache {    public static void clean(String key) {        String sql = "delete from " + StaticConstant.SQLCACHE + " where  key=‘" + key + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    public static void save(CacheModel cache) {        String sql = "select key from " + StaticConstant.SQLCACHE + " where key=‘" + cache.key + "‘";        if (StaticVariable.mSqLiteOper.query(sql, "key").size() > 0) {            StaticVariable.mSqLiteOper.update(StaticConstant.SQLCACHE,                    " where key=‘" + cache.key + "‘",                    cache,                    CacheModel.class);        } else {            StaticVariable.mSqLiteOper.insert(StaticConstant.SQLCACHE,                    cache,                    CacheModel.class);        }    }    public static CacheModel read(String key) {        String sql = "select * from " + StaticConstant.SQLCACHE + " where key=‘" + key + "‘";        List<CacheModel> temp = StaticVariable.mSqLiteOper.query(sql, CacheModel.class);        if (temp.size() > 0)            return temp.get(0);        else            return null;    }}

  sqlite緩衝類都是根據業務來寫的,不同app有不同業務,業務也在隨時變化,所以這個類僅供參考。

  既然都寫到緩衝了,順便就把我另一個例子也存檔一下吧。

  推送是大部分app必備的功能,而一個體驗良好的app,推送到達app端後是持久存在的,直到被使用者消費掉,例如的紅點未讀提醒。

  這就需要實現推送訊息的緩衝,而當推送訊息類型很多時,緩衝管理就十分麻煩,這時就必須使用資料庫來管理推送緩衝。

  

public class PushMsgCache {    /**     * 首頁已讀(任務通知裡面)     */    public static void read1(String uid) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE + " SET state = 2 WHERE state=1 and " +                " type!=‘" + StaticConstant.對話 + "‘ and " +                " type!=‘" + StaticConstant.系統通知 + "‘ and " +                " type!=‘" + StaticConstant.銷售新使用者 + "‘ and userid = ‘" + uid + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 特定通知1級已讀設定     */    public static void read1(String uid, String msgType) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE +                " SET state = 2 WHERE state in(1,2) and userid = ‘" + uid + "‘ and type=‘" + msgType + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 2級通知頁面已讀     */    public static void read2(String uid, String msgType) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE +                " SET state = 3 WHERE state in(1,2) and userid = ‘" + uid + "‘ and type=‘" + msgType + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 詳情已讀     */    public static void read3(String uid, String msgType) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE +                " SET state = 4 WHERE state in(1,2,3) and userid = ‘" + uid + "‘ and type=‘" + msgType + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 列表已讀     */    public static void readwechatlist(String uid) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE + " SET state = 2 WHERE state=1 and " +                " type=‘" + StaticConstant.對話 + "‘ and userid = ‘" + uid + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 訊息已讀     */    public static void readwechat(String uid, String cid) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE +                " SET state = 3 WHERE state in(1,2) and userid = ‘" + uid + "‘ and targetid=‘" +                cid + "‘ and type=‘" + StaticConstant.對話 + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 跟進詳情回複已讀     */    public static void readgjxqhf2(String uid, String cid) {        String sql = "UPDATE " + StaticConstant.NOTICECACHE +                " SET state = 3 WHERE state in(1,2) and userid = ‘" + uid + "‘ and targetid=‘" +                cid + "‘ and type=‘" + StaticConstant.銷售新使用者 + "‘";        StaticVariable.mSqLiteOper.execSql(sql);    }    /**     * 推送訊息入庫     *     * @param json 推送過來的訊息對象的json     */    public static void save(String json) {        Gson gson = new Gson();        NoticeCacheModel model = new NoticeCacheModel();        PushReceiverModel push = gson.fromJson(json, PushReceiverModel.class);        model.setType(push.getMessageType());        model.setMsg(gson.toJson(push));        model.setTime(StaticMethod.getNowTimeStamp() + "");        model.setTargetid(push.getUid() + "");        if (push.getAdvid() != 0) {            model.setUserid(push.getAdvid() + "");        } else {            model.setUserid(push.getAdvisorid() + "");        }        model.setState(1);        StaticVariable.mSqLiteOper.insert(StaticConstant.NOTICECACHE, model, NoticeCacheModel.class);    }    /**     * 讀取推送訊息     *     * @param pageName 取資料的頁面名稱     */    public static List<PushReceiverModel> query(String pageName) {        String sql = "";        switch (pageName) {            case "xsgw_main"://尋找所有未讀的推送資訊                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state=1 and" +                        " type!=‘" + StaticConstant.對話 + "‘ and " +                        " type!=‘" + StaticConstant.搶客戶 + "‘ and " +                        " type!=‘" + StaticConstant.系統通知 + "‘ and " +                        "type!=‘" + StaticConstant.銷售新使用者 + "‘" +                        "order by time desc";                break;            case "xsgw_msgbox":                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state in(1,2) order by time desc";                break;            case "xsjl_main":                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state=1 and" +                        " type!=‘" + StaticConstant.對話 + "‘ and " +                        " type!=‘" + StaticConstant.搶客戶 + "‘ and " +                        " type!=‘" + StaticConstant.系統通知 + "‘ and " +                        "type!=‘" + StaticConstant.銷售新使用者 + "‘" +                        "order by time desc";                break;            case "xsjl_msgbox":                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state in(1,2)  order by time desc";                break;            case "wechat":                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state in(1,2) and type=‘" + StaticConstant.對話 + "‘ order by time desc";                break;            case "xsgw_main_activity":                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state=1 order by time desc";                break;            case "newnotice":                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state in(1,2,3) and type=‘" + StaticConstant.經理通知 + "‘";                break;            case "system"://未讀系統通知                sql = "select * from " + StaticConstant.NOTICECACHE + " where userid=‘" +                        StaticVariable.uid + "‘ and state in(1,2) and type=‘" + StaticConstant.系統通知 + "‘";                break;            default:                return null;        }        List<NoticeCacheModel> temp = StaticVariable.mSqLiteOper.query(sql, NoticeCacheModel.class);        if (temp.size() > 0) {            Gson gson = new Gson();            List<PushReceiverModel> result = new ArrayList<>();            for (NoticeCacheModel item : temp) {                result.add(gson.fromJson(item.getMsg(), PushReceiverModel.class));            }            return result;        } else            return null;    }}

  對推送訊息的處理,我採用json來存放到資料庫中,使用gson來完成資料的序列化和還原序列化。

  這個類裡面的核心方法是save(訊息入庫)和query(未讀訊息查詢),readxxx系列方法則是根據不同業務產生的訊息被消費方法,作用是把訊息置為已消費。

  因為我目前開發都是小團隊模式,1-5人之內,對代碼的抽象需求不大,所以寫類的時候我更多的是考慮代碼易讀和修改便捷,覺得水平太差的請輕噴.

android sqlite orm

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.