默认的升级方案是会删除表后在创建
//默认实现
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name) {
super(context, name);
}
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true); //删除表
onCreate(db); //重新新建
}
}
为了保留就数据,所以要复写onUpgrade方法。大概有两种方式
核心很简单,就是升级触发回调时 通过判断数据库的升级版本号执行对于的sql 注入字段,或表
例如:为LoginInfoResult 增加一个Level 等级字段
1.对应的实体类增加 Level字段 并编译生成
@Entity
public class LoginInfoResult implements Cloneable {
...
private String Level;
...
}
2.修改版本号并且执行sql语句进行升级
greendao {
schemaVersion 2
}
在application初始化时复写onUpgrade方法
// do this once, for example in your Application class
val helper = object: DaoMaster.DevOpenHelper(this, "wecut-db"){
override fun onUpgrade(db: Database?, oldVersion: Int, newVersion: Int) {
//注释默认的实现
//super.onUpgrade(db, oldVersion, newVersion)
val startVersion = oldVersion + 1
//for循环避免有旧版本升级上来有未执行到sql
for (i in startVersion..newVersion) {
when(i){
//当前新版本如果是2的时候增加一个Level字段
2->{
val sql = "ALTER TABLE "+LoginInfoResultDao.TABLENAME+" ADD column Level TEXT "
db?.execSQL(sql)
}
3->{.其他版本的sql.}
4->{.其他版本的sql.}
}
}
}
}
3.导出数据库进行查看结果
思路
例如: 在LoginInfoResult增加 Level2 字段
1.对应的实体类增加 Level2字段 并编译生成
@Entity
public class LoginInfoResult implements Cloneable {
...
private String Level2;
...
}
2.修改版本号并且执行sql语句进行升级
greendao {
schemaVersion 2
}
在application初始化时复写onUpgrade方法
val helper = object: DaoMaster.DevOpenHelper(this, "wecut-db"){
override fun onUpgrade(db: Database?, oldVersion: Int, newVersion: Int) {
//super.onUpgrade(db, oldVersion, newVersion)
if(db!=null){
if(oldVersion<newVersion){
//传入要备份的DAO 创建临时表
GreenDaoCompatibleUpdateHelper.generateTempTables(db,
LoginInfoResultDao::class.java,
VipPayInfoDao::class.java)
//调用默认的方式删除和创建新的表格
super.onUpgrade(db, oldVersion, newVersion)
//传入DAO 还原数据
GreenDaoCompatibleUpdateHelper.restoreData(db,
LoginInfoResultDao::class.java,
VipPayInfoDao::class.java)
}
}else{
//删除和创建新的表格
DaoMaster.dropAllTables(db, true)
DaoMaster.createAllTables(db, false)
}
}
}
/**
* @author: Lai
* @createDate: 2019-12-13 15:28
* @description:
*/
class GreenDaoCompatibleUpdateHelper {
companion object{
//系统表
private val SQLITE_MASTER = "sqlite_master"
//系统临时表
private val SQLITE_TEMP_MASTER = "sqlite_temp_master"
/**
* 生成临时表
* @param sqLiteDatabase Database
* @param clazz 要备份的DAO
*/
fun generateTempTables(sqLiteDatabase: Database,
vararg clazz: Class<out AbstractDao<*, *>>) {
clazz.forEach {
val daoConfig = DaoConfig(sqLiteDatabase, it)
//获取当前数据库名称
val tableName = daoConfig.tablename
try {
//如果表格存在
if (isTableExists(sqLiteDatabase, false, tableName)) {
//如果存在临时表则删除
val tempTableName = tableName + "_TEMP"
val dropTableStringBuilder = StringBuilder()
dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";")
sqLiteDatabase.execSQL(dropTableStringBuilder.toString())
//tableName的数据copy一份都临时表
val insertTableStringBuilder = StringBuilder()
insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName)
insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";")
sqLiteDatabase.execSQL(insertTableStringBuilder.toString())
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
}
/**
* 还原数据
* * @param sqLiteDatabase Database
* @param clazz 要还原的DAO
*/
fun restoreData(sqLiteDatabase: Database,
vararg clazz: Class<out AbstractDao<*, *>>) {
clazz.forEach {
val daoConfig = DaoConfig(sqLiteDatabase, it)
val tableName = daoConfig.tablename
val tempTableName = daoConfig.tablename + "_TEMP"
if (isTableExists(sqLiteDatabase, true, tempTableName)) {
try {
// 获取对于的表格字段数据
val newTableInfos = TableInfo.getTableInfo(sqLiteDatabase, tableName)
val tempTableInfos = TableInfo.getTableInfo(sqLiteDatabase, tempTableName)
val selectColumns = ArrayList<String>()
val intoColumns = ArrayList<String>()
for (tableInfo in tempTableInfos) {
if (newTableInfos.contains(tableInfo)) {
val column = "`" + tableInfo.name + "`"
intoColumns.add(column)
selectColumns.add(column)
}
}
// NOT NULL columns list
for (tableInfo in newTableInfos) {
if (tableInfo.notnull && !tempTableInfos.contains(tableInfo)) {
val column = '`'.toString() + tableInfo.name + '`'.toString()
intoColumns.add(column)
val value = if (tableInfo.dfltValue != null) {
"'" + tableInfo.dfltValue + "' AS "
} else {
"'' AS "
}
selectColumns.add(value + column)
}
}
//拼接好后执行sql还原数据
if (intoColumns.size != 0) {
val insertTableStringBuilder = StringBuilder()
insertTableStringBuilder.append("REPLACE INTO ").append(tableName).append(" (")
insertTableStringBuilder.append(TextUtils.join(",", intoColumns))
insertTableStringBuilder.append(") SELECT ")
insertTableStringBuilder.append(TextUtils.join(",", selectColumns))
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";")
val sql = insertTableStringBuilder.toString()
sqLiteDatabase.execSQL(sql)
}
//删除临时表的数据
val dropTableStringBuilder = StringBuilder()
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName)
sqLiteDatabase.execSQL(dropTableStringBuilder.toString())
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
}
}
private fun isTableExists(db: Database?, isTemp: Boolean, tableName: String): Boolean {
if (db == null || TextUtils.isEmpty(tableName)) {
return false
}
val dbName = if (isTemp) SQLITE_TEMP_MASTER else SQLITE_MASTER
val sql = "SELECT COUNT(*) FROM $dbName WHERE type = ? AND name = ?"
var cursor: Cursor? = null
var count = 0
try {
cursor = db.rawQuery(sql, arrayOf("table", tableName))
if (cursor == null || !cursor.moveToFirst()) {
return false
}
count = cursor.getInt(0)
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return count > 0
}
}
class TableInfo {
var cid: Int = 0
var name: String? = null
var type: String? = null
var notnull: Boolean = false
var dfltValue: String? = null
var pk: Boolean = false
override fun equals(o: Any?): Boolean {
return this === o || (o != null
&& javaClass == o.javaClass
&& name == (o as TableInfo).name)
}
override fun toString(): String {
return "TableInfo{" +
"cid=" + cid +
", name='" + name + '\''.toString() +
", type='" + type + '\''.toString() +
", notnull=" + notnull +
", dfltValue='" + dfltValue + '\''.toString() +
", pk=" + pk +
'}'.toString()
}
companion object {
fun getTableInfo(db: Database, tableName: String): List<TableInfo> {
val sql = "PRAGMA table_info($tableName)"
val cursor = db.rawQuery(sql, null) ?: return ArrayList()
var tableInfo: TableInfo
val tableInfos = ArrayList<TableInfo>()
while (cursor.moveToNext()) {
tableInfo = TableInfo()
tableInfo.cid = cursor.getInt(0)
tableInfo.name = cursor.getString(1)
tableInfo.type = cursor.getString(2)
tableInfo.notnull = cursor.getInt(3) == 1
tableInfo.dfltValue = cursor.getString(4)
tableInfo.pk = cursor.getInt(5) == 1
tableInfos.add(tableInfo)
// printLog(tableName + ":" + tableInfo);
}
cursor.close()
return tableInfos
}
}
}
}