zoukankan      html  css  js  c++  java
  • 自己动手写个Android数据库orm框架,支持关联关系,数据懒加载

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

  • 相关阅读:
    2010全球最值得模仿的230个网站 dodo
    IIS支持解析json dodo
    很好用的界面设计工具——Balsamiq dodo
    git本地分支目录和远程服务器的分支目录不一样的同步方法
    中新赛克——基于工业资产全息画像的工业互联网安全监测平台 规格严格
    解决redis requires ruby version 2.3.0[转载] 规格严格
    fpm包安装 规格严格
    git本地分支目录和远程服务器的分支目录不一样的同步方法[转】 规格严格
    MyBatis逆向工程generatorConfig配置文件的Table中generatedKey的作用[转载] 规格严格
    How to set character_set_database and collation_database to utf8 in my.ini 规格严格
  • 原文地址:https://www.cnblogs.com/stay/p/3054682.html
Copyright © 2011-2022 走看看