自己動手寫個Android資料庫orm架構,支援關聯關係,資料懶載入

來源:互聯網
上載者:User

因為ios用的是sqlite資料庫,所以公司要求我也用sqlite,大家都知道sqlite的sql不怎麼好用,尤其是我們app裡至少有46張表,資料量最多能達到2G,所以不重新封裝一層,越到後期怕是越難維護吧,代碼量也不少。

所以我在sqlite上又封裝了一層,參照對象型資料庫的原理也做了這樣module。類似hibernate。

a.首先是欄位咯,entity裡的properties不一定全要映射到資料庫中,所以我定義了

DBColumn : String columnName ,String type ,Class clz.(如果你需要用index和trigger也是如此)

資料庫5種類型可以寫個tool和property的資料類型做映射(當然還有1-1,1-*,*-* 關係)

b.介面設計,如果以後不用sqlite,選用其他資料庫了,為了這樣的考慮,所以介面要設計好

- newOrUpdate(T) - delete(T) -query(sql,String[] args) -query(Class,String[] args) -close()

這裡sqlite有replace()方法,會自動去判斷是需要insert還是update。推薦使用。

介面定義好了,就是資料庫實現了。這裡就會有兩個問題:

1.insert/update如何構建ContentValues,如果要想automatic,那麼必須要用反射了。之前有提到要定義映射的DBColumn,那麼有了每個欄位的定義,通過反射去拿值構建ContentValues應該不是什麼難事了。比較難搞定的是表關係。1-1比較好弄,只是把id存好就可以了。1-*關係 這個關係是存在*的這張表,所以不做任何事情,*-*就比較麻煩,需要存到關聯表中。代碼如下:

case DBColumn.FIELD_TYPE_TMANY:// save the objects'

List<? extends Persistent> list = (List<? extends Persistent>) method.invoke(t, null);

if (list != null && list.size() > 0) {

ContentValues tValues = null;

HashMap<String, ContentValues> tMap = null;

for (Persistent persistent : list) {

tValues = new ContentValues();

tMap = new HashMap<String, ContentValues>();

tValues.put(Repository.PK1, t.realGuid());

tValues.put(Repository.PK2, persistent.realGuid());

tMap.put(DBUtilities.getAssosiationTableName(clz.column.columnName), tValues);

bindArgs.add(tMap);

}

}

2.query出來如何setValue.這裡當然需要Cursor對象咯。同樣的,通過反射給DTO對象賦值,普通對象沒什麼問題,關鍵是1-1,1-*,*-* 都是其他的DTO對象或者是ArrayList<DTO>,所以這裡就引出了很重要的概念:代理(Proxy)。因為Android提供的java代理不能很好用,之後試過CGLib庫裡的Proxy,雖然好用,但是在Android是不能用,悲劇。所以我leader讓我試試AspectJ。會用Spring的人都知道面向切面把。AspectJ就是做這個的。

首先,有這樣一個概念,如果一次就把DTO對象裡的property都setValue,那麼需要查好幾次表把。因為有1-1等那些關係。如果每次都這樣,是不是會引起不必要的浪費,所以我們需要一個lazy load來載入1-1等那些資料。那麼lazyload如何?呢。有了AspectJ就好辦了。首先DTO提供一個有參的構造方法。這裡參數當然是id咯。至於1-*等關係,你就需要extends ArrayList了。同樣是有參的構造方法。把ids或者querySql傳過去,當然還要指明T。然後重寫ArrayList的方法,add(T),size(),remove(T)...例如:

@Override

public T get(int location) {

if (cache.containsKey(location)) {

if (cache.get(location) != null) {

return (T) cache.get(location).get();

} else {

cache.remove(location);

return createObjFromCursor(location);

}

} else {// get obj from cursor and save it into map

return createObjFromCursor(location);

}

}

相信看了代碼大家都很明白了把,取值是從cache或者db裡面取值,然後就是setValue的具體方法了,以下是部分代碼:

case DBColumn.FIELD_TYPE_TONE:

Constructor con = column.clz.getConstructor(String.class);

method = targetClass.getMethod(generateMethodName(false, column.columnName,isBooleanType),new Class[] { column.clz });

method.invoke(t, con.newInstance(cursor.getString(index)));

break;

case DBColumn.FIELD_TYPE_TMANY:

method = targetClass.getMethod(generateMethodName(false, column.columnName,isBooleanType),new Class[] { DTOList.class });

method.invoke(t,new DTOArray(column.clz, DBUtilities.getTManyGuidsStmt(targetClass, column),DBUtilities.getTManyQueryStmt(targetClass,column), new String[] { t.realGuid() }));

break;

case DBColumn.FIELD_TYPE_MMANY:

method = targetClass.getMethod(generateMethodName(false, column.columnName,isBooleanType),new Class[] { DTOList.class });

method.invoke(t,new DTOArray(column.clz, null, DBUtilities.getMManyQueryStmt(column.clz),new String[] { t.realGuid(),getObjectType(targetClass) }));

break;

注意Cursor,要選擇合適的場合close,否則~你懂的~~

寫的這麼複雜,確實有點傷腦筋,但是架構搭好了之後(花了大概一個月時間)就在也不用管了。比起用別人的資料庫架構,自己封裝一個簡易的架構是不是更方便更省心更安全呢。

這裡推薦一些android的資料庫架構:

對象型資料庫:Perst,DB4O.

關係型資料庫架構:Android orm ,ormlite.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.