因为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.

posted on 2013-05-02 15:08  stay  阅读(1952)  评论(1编辑  收藏  举报