Orm之Reflect(二)

Orm_Reflect_DB——Reflect(二)

ORM系列章節(點擊查閱)

前面講了Orm以及XMl解析,並回顧了Reflect的幾個常用知識點,那麼現在我們即將進入正題,將XMl、實體類、數據庫字段、Reflect結合起來實現數據庫操作類的封裝,這也是整個小框架的核心所在。
首先我們新建dao目錄並創建BaseDao類用來封裝數據庫操作:
先貼構造函數代碼如下:
    /**
     * @param helper
     */
    public BaseDao(BaseDatabaseHelper helper, Class<T> beanClass) {
        this.db = helper.getWritableDatabase();
        this.beanClass = beanClass;
        //根據文件名獲取對應orm
        this.orm = DBConfig.mapping.get(beanClass.getSimpleName() + ".orm.xml");
    }
這裏我們傳入一個BaseDatabaseHelper對象(我們Orm部分提到過),這個很好理解,用於初始化SQLiteDatabase,進行數據操作。那麼另一個Class<T>這個對象類型又是什麼呢,前一章我們有講過Reflect的常用知識點,其中不管是獲取Java類中的方法、成員變量還是實例化類都需要一個類的對象,那就是Class<?>,我們這裏有用到泛型,主要用於限定對象類型,也方便代碼拓展;另一個orm參數即爲XMl解析後得到的對象,通過文件名獲取在mapping集合中相對應的orm。Class<?>有了,SQLiteDatabase有了,Orm也有了,準備工作齊全,可以開始數據庫操作方法的封裝了。
我們這裏重點講一下insert操作,其他可通過閱讀源碼獲得:Orm_Reflect_DB
這裏面重點代碼都在putValues(T t)這個方法中,我先貼一下ContentValues集合添加對象的方法:
public long insert(T t) {
        long length = -1;
        if (db != null) {
            db.beginTransaction();
            try {
//將參數封裝到ContentValues集合中
                ContentValues values = putValues(t);
                length = db.insert(orm.getTableName(), null, values);
                db.setTransactionSuccessful();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                db.endTransaction();
            }
        }
        return length;
    }
看到這裏我們可以知道的是第一個參數是String類型,代表數據庫表中的字段名,第二個參數則是字段對應的值,那麼問題來了,我們只傳入一個T對象,怎麼獲取到字段名和字段對應的值,還有這個put方法又改用哪個,是不是頭暈了。不用怕,我們一個個解決問題,首先怎麼獲取到字段名,其實簡單,我們的構造函數中得到Orm屬性中不就包含了Key和Item對象,字段名不就是他們兩的成員變量,那麼fildName就解決了,至於字段對應的值我們是不是可以通過反射的方式從傳進來的T對象中獲取,put方法同理,說了這麼多,還是貼代碼實在:
 private ContentValues putValues(T t) throws Exception {
        //因爲無法確定values.put()參數類型,這裏用到反射調用values的put方法
        ContentValues values = new ContentValues();
        Key key = orm.getKey();
        //判斷key時候爲自增長,否才進行賦值
        if (!key.isIdentity()) {
            //通過反射獲取ContentValues的put方法
            Method put = values.getClass().getDeclaredMethod("put",
                    new Class[]{String.class, Class.forName(key.getType())});
            //獲取實體類的成員變量
            Field field = beanClass.getDeclaredField(key.getProperty());
            //設置不做權限檢查(private、protect等都可以取到值)檢查
            field.setAccessible(true);
            //獲取成員變量的值
            Object value = field.get(t);
            put.invoke(values, key.getColumn(), value);
        }
        for (Item item : orm.getItems()) {
            Method put = values.getClass().getDeclaredMethod("put",
                    new Class[]{String.class, Class.forName(item.getType())});
            Field field = beanClass.getDeclaredField(item.getProperty());
            field.setAccessible(true);
            Object value = field.get(t);
            put.invoke(values, item.getColumn(), value);
        }
        return values;
    }
是不是屌爆了,用過Orm或者Gson解析的是不是發現這種直接傳對象集合就能得到結果的方法很眼熟,不錯,看了這篇文章你會發現,其實就這麼簡單。
方法也封裝好了,接下來我們要試下結果如何,黑貓、白貓,能抓到老鼠纔是好貓。
我們需要建立Student表專屬的dao類,方便建立model以及解耦:
public class StudentDao extends BaseDao<Student> {
	public StudentDao(BaseDatabaseHelper helper) {
		super(helper,Student.class);
		// TODO Auto-generated constructor stub
	}
	public Orm getOrm(){
		return super.getOrm();
	}
}
注意這裏我們需要將Student的字節碼文件屬性傳給BaseDao類,建立自己的專屬dao,至於界面怎麼寫我就不多說了,畢竟跟我們要講的東西關係不大,直接貼效果圖:

我將其中公共部分的代碼剝離了出來,寫成了一個library,包含在源碼中:Orm_Reflect_DB,歡迎大家指正,並提出修改意見,下一章我會大概講解一下如何在自己項目中使用。雖然東西很小,但很實用,希望能對您有幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章