一、背景
平常咱们使用数据库的时候,基本操作都差不太多,增,删,改,查,但如果操作不同的数据时,就需要写较多的重复的代码,仅仅是因为操作的类对象变化了。下面咱们就通过泛型去封装一层BaseDao,减少后期的模板代码。
二、封装
abstract class BaseDao<T> {
/**
* 添加单个对象
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insert(obj: T): Long
/**
* 添加数组对象数据
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insert(vararg objs: T): LongArray?
/**
* 添加对象集合
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insert(personList: List<T>): List<Long>
/**
* 根据对象中的主键删除(主键是自动增长的,无需手动赋值)
*/
@Delete
abstract fun delete(obj: T)
/**
* 根据对象中的主键更新(主键是自动增长的,无需手动赋值)
*/
@Update
abstract fun update(vararg obj: T): Int
fun deleteAll(): Int {
val query = SimpleSQLiteQuery(
"delete from $tableName"
)
return doDeleteAll(query)
}
fun findAll(): List<T>? {
val query = SimpleSQLiteQuery(
"select * from $tableName"
)
return doFindAll(query)
}
fun find(id: Long): T? {
val query = SimpleSQLiteQuery(
"select * from $tableName where id = ?", arrayOf<Any>(id)
)
return doFind(query)
}
/**
* [params] 列名
* [value] 列的值
*/
fun deleteByParams(params: String, value: String): Int {
val query = SimpleSQLiteQuery("delete from $tableName where $params='${value}'")
Log.d("ez", "deleteByParams: ${"delete from $tableName where $params='${value}'"}")
return doDeleteByParams(query)
}
/**
* 分页查询,支持传入多个字段,但必须要按照顺序传入
* key = value,key = value 的形式,一一对应(可以使用 stringbuilder 去构造一下,这里就不演示了)
*/
fun doQueryByLimit(vararg string: String, limit: Int = 10, offset: Int = 0): List<T>? {
val query =
SimpleSQLiteQuery("SELECT * FROM $tableName WHERE ${string[0]} = '${string[1]}' limit $limit offset $offset")
return doQueryByLimit(query)
}
/**
* 降序分页查询
*/
fun doQueryByOrder(vararg string: String, limit: Int = 10, offset: Int = 10): List<T>? {
val query =
SimpleSQLiteQuery("SELECT * FROM $tableName ORDER BY ${string[0]} desc limit '${limit}' offset '${offset}'")
return doQueryByLimit(query)
}
/**
* 获取表名
*/
val tableName: String
get() {
val clazz = (javaClass.superclass.genericSuperclass as ParameterizedType)
.actualTypeArguments[0] as Class<*>
val tableName = clazz.simpleName
Log.d("ez", "getTableName: -->$tableName")
return tableName
}
@RawQuery
protected abstract fun doFindAll(query: SupportSQLiteQuery?): List<T>?
@RawQuery
protected abstract fun doFind(query: SupportSQLiteQuery?): T
@RawQuery
protected abstract fun doDeleteAll(query: SupportSQLiteQuery?): Int
@RawQuery
protected abstract fun doDeleteByParams(query: SupportSQLiteQuery?): Int
@RawQuery
protected abstract fun doQueryByLimit(query: SupportSQLiteQuery?): List<T>?
@RawQuery
protected abstract fun doQueryByOrder(query: SupportSQLiteQuery?): List<T>?
}
因为Room的Query注解需要一个常量,这里就无法通过泛型去解决,所以就使用了SupportSQLiteQuery类和@RawQuery注解,这样咱们就可以通过sql语句来封装一些通用的操作,就解决了Query注解无法直接使用泛型的问题,详细用法请看上面的方法。
三、使用
@Entity
class Person {
@PrimaryKey(autoGenerate = true)
var id: Long?
var bh: String
var name: String? = null
var loginName: String? = null
var feature: ByteArray? = null
var isPolice: Boolean = false
constructor(
id: Long? = null,
name: String?,
feature: ByteArray? = null,
bh: String,
loginName: String? = null,
isPolice: Boolean = false
) {
this.id = id
this.name = name
this.feature = feature
this.bh = bh
this.loginName = loginName
this.isPolice = isPolice
}
override fun toString(): String {
return "Person(id=$id, bh=$bh, name=$name,loginName=$loginName, isPolice=$isPolice)"
}
}
@Dao
abstract class StudentDao : BaseDao<Person>() {
}
这里咱们只要去继承BaseDao然后传入需要操作的对象类型即可,通用的操作已封装在上层,无需再重复写了
构建 RoomDatabase
@Database(entities = [Person::class],version = 1,exportSchema = false)
abstract class DBFactory :RoomDatabase(){
abstract fun getStudent():StudentDao
companion object{
private const val DB_NAME = "DBFactory.db"
@Volatile
private var dbFactory:DBFactory?=null
@Synchronized
fun getInstance(context: Context):DBFactory{
if (dbFactory == null) {
dbFactory = create(context)
}
return dbFactory!!
}
fun create(context: Context):DBFactory{
return Room.databaseBuilder(context,DBFactory::class.java, DB_NAME).build()
}
}
}