Android开发知识集Kotlin开发指南Android知识

使用Kotlin函数简化数据库访问

2017-04-26  本文已影响328人  027f63d16800

kotlin的函数相比java,提供了更多的特性,比如扩展函数和操作符重载,因此可以很容易地实现下面的语句:

+ entity  //往数据库插入一条数据

首先,在dao层定义好访问数据库的通用接口并实现一个通用的dao层类,这里面的所有方法都要求是泛型方法
下面是我自己封装的一个简单的通用dao

open class BaseDBAccessorImpl<T>: IBaseDBAccessor<T>{
//dao层使用了hirbernate,但是没有使用ioc框架,需要手动去获取session
//SessionFac是我自己封装的一个工具类,里面有个counter计数器对同个线程的getSession和close调用进行计数,第一次get开启事务,最后一次close关闭事务
    override val session: Session=SessionFac.getSession()
    override fun close(){
        SessionFac.closeSession(session)
    }
    override fun insert(t: T) {
        session.saveOrUpdate(t)
    }
    override fun delete(id: Int,clazz:Class<T>) {
        var obj=session.get(clazz,id)
        session.delete(obj)
    }
    override fun delete(t: T) {
        session.delete(t)
    }
    override fun getCount(clazz:Class<T>): Int
            =(session.createQuery("select count(*) from ${clazz.simpleName}")
            .uniqueResult() as Long).toInt()
    override fun getListByPage(clazz:Class<T>, pageNo: Int, rows: Int)
            = session.createQuery("from ${clazz.simpleName}")
            .setFirstResult((pageNo-1)*rows)
            .setMaxResults(rows)
            .list() as List<T>
    override fun getObj(clazz:Class<T>,id: Int): T = session.get(clazz,id) as T
}

现在已经有dao层了,如果没有使用ioc框架,那么每次使用dao层都要先实例化一个dao层的对象,然后调用dao层的方法实现我们的业务需求。
kotlin支持top-level函数,我们可以直接声明一系列函数把对数据库的访问封装起来,比如插入一条记录:

inline fun <T> T.insert(){
    val acc= NewDatabase<T>()
    acc.insert(this)
    acc.close()
}

在这里我们声明一个泛型的extension函数而且receiver就是泛型参数T
这个函数的效果就是:
对任意的entity实体对象obj,使用:

obj.insert()

就是将obj本身作为一条记录插入数据库
因为是一个泛型函数,所以无论是什么类型的entity都可以直接插入数据库
那么问题来了,如果调用者不是一个entity呢?那么dao层内部肯定会直接抛出异常
会抛异常的代码肯定不是好代码,而使用了泛型,所有的对象都可以调用这个函数,
因此,我们需要在调用dao层之前先做安全检查
我们重新定义一个函数方便重用:

inline fun <T> T.checkobj():Boolean{
    if((this as Any).javaClass.getAnnotation(Entity::class.java)==null)
        return false
    return true
}

接着对原函数修改:

inline fun <T> T.insert(){
    if(!checkobj())
        return
    val acc= NewDatabase<T>()
    acc.insert(this)
    acc.close()
}

现在,如果是非@entity对象调用insert将直接返回
接着来定义:

inline operator fun <T> T.unaryPlus(){
    insert()
}

在这里我们定义了一个重载了一元运算符+的函数,而这个函数同上面的insert一样是一个泛型的extension函数,在里面我们直接重用上面的insert函数来实现功能逻辑
那么现在,我们就可以随意使用+ entity-obj的写法来插入一条数据到数据库中了

到此,我们就完成了对数据插入操作的封装
而对于其他的操作,比如删除可以直接- fund或者Fund::class - id,查找指定id的记录可以像Fund::class[id],跟上面的差别无非就是重载的运算符和函数的泛型参数个数有些许差别

通过对dao层的调用进行简单的封装,不仅仅使用更加方便,而且更加形象
记录的增删就是加减操作,而查询数据可以像访问数组一样便利

上面所有的函数里面,dao层的对象都是通过NewDatabase()来获取的

inline fun <T> NewDatabase():IBaseDBAccessor<T>{
    return BaseDBAccessorImpl<T>()
}

上面所有的函数都被定义成了inline,实际运行和直接实例化一个dao层对象来访问数据库是一样的,并没有太多额外的运行开销

上一篇 下一篇

猜你喜欢

热点阅读