本章節講述GreenDao數據庫升級
在版本迭代時,我們經常需要對數據庫進行升級,而GreenDAO默認的DaoMaster.DevOpenHelper在進行數據升級時,會把舊錶刪除,然後創建新表,並沒有遷移舊數據到新表中,從而造成數據丟失。
1.代碼說明
獲取DevOpenHelper幫助類
//創建數據庫shop.db 創建SQLite數據庫的SQLiteOpenHelper的具體實現
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "greendaodemo.db", null);
DevOpenHelper 部分源碼
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方法中 默認的DevOpenHelper 類是直接將所有的表都刪除了然後重新執行onCreate(db)方法創建新表。這在實際中是不可取的,因爲我們在絕大數情況下是需要保留原始數據的。所以需要解決這一問題。
2.代碼舉例
版本爲1時
greendao {
// 版本號
schemaVersion 1
//greendao輸出dao的數據庫操作實體類文件夾
daoPackage 'com.wjn.androiddbdemo.greendao'
//greenDao實體類包文件夾
targetGenDir 'src/main/java'
}
插入數據+查詢數據
package com.wjn.androiddbdemo.activity.greendao;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.wjn.androiddbdemo.MyApplication;
import com.wjn.androiddbdemo.R;
import com.wjn.androiddbdemo.greendao.UserInfo;
import com.wjn.androiddbdemo.greendao.UserInfoDao;
import com.wjn.androiddbdemo.utils.ui.StatusBarUtil;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.ArrayList;
import java.util.List;
public class GreenDaoUpdateActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView1;
private TextView textView2;
private TextView textView3;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_greendaoupdate);
initView();
}
/**
* 初始化各種View
*/
private void initView() {
//根據狀態欄顏色來決定 狀態欄背景 用黑色還是白色 true:是否修改狀態欄字體顏色
StatusBarUtil.setStatusBarMode(this, false, false, R.color.colorPrimary);
textView1 = findViewById(R.id.activity_greendaoupdate_textview1);
textView2 = findViewById(R.id.activity_greendaoupdate_textview2);
textView3 = findViewById(R.id.activity_greendaoupdate_textview3);
textView = findViewById(R.id.activity_greendaoupdate_textview);
textView1.setOnClickListener(this);
textView2.setOnClickListener(this);
textView3.setOnClickListener(this);
}
/**
* 各種點擊事件的方法
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_greendaoupdate_textview1://插入數據
insertUser();
break;
case R.id.activity_greendaoupdate_textview2://查詢數據
List<UserInfo> list=queryUserList();
StringBuilder sbBuilder = new StringBuilder();
for(int i=0;i<list.size();i++){
UserInfo userInfo=list.get(i);
Long id=userInfo.getId();
String name=userInfo.getName();
String age=userInfo.getAge();
sbBuilder.append("ID:" + id + "\n");
sbBuilder.append("姓名:" + name + "\n\n");
sbBuilder.append("年齡:" + age + "\n\n");
}
textView.setText(sbBuilder.toString());
break;
case R.id.activity_greendaoupdate_textview3://更新後查詢數據
break;
default:
break;
}
}
/**
* 插入多條條記錄
*/
public void insertUser() {
UserInfo userInfo=new UserInfo();
userInfo.setName("張三");
userInfo.setAge("29");
UserInfo userInfo1=new UserInfo();
userInfo1.setName("李四");
userInfo1.setAge("39");
UserInfo userInfo2=new UserInfo();
userInfo2.setName("旺旺");
userInfo2.setAge("19");
UserInfo userInfo3=new UserInfo();
userInfo3.setName("王偉");
userInfo3.setAge("59");
List<UserInfo> list=new ArrayList<>();
list.add(userInfo);
list.add(userInfo1);
list.add(userInfo2);
list.add(userInfo3);
UserInfoDao userInfoDao= MyApplication.getDaoInstant().getUserInfoDao();
userInfoDao.insertInTx(list);
}
/**
* 查詢數據列表 姓名=“張三”
*/
public List<UserInfo> queryUserList() {
UserInfoDao userInfoDao= MyApplication.getDaoInstant().getUserInfoDao();
QueryBuilder<UserInfo> qb = userInfoDao.queryBuilder();
List<UserInfo> list = qb.list();
return list;
}
}
結果
版本爲2時
greendao {
// 版本號
schemaVersion 2
//greendao輸出dao的數據庫操作實體類文件夾
daoPackage 'com.wjn.androiddbdemo.greendao'
//greenDao實體類包文件夾
targetGenDir 'src/main/java'
}
再次查詢數據結果
這就證明默認情況下,GreenDao數據庫升級時會把原始數據刪除。
解決方案
解決方案1:自己手動修改實體類和相應的DaoMaster.OpenHelper(DaoMaster.DevOpenHelper)類
由上可知,在GreenDao數據庫升級時,要想保留原始數據要操作DaoMaster.OpenHelper(DaoMaster.DevOpenHelper)類的onUpgrade方法。由於GreenDao數據庫的建表是按實體類創建的所以也要修改實體類。
修改前的實體類
package com.wjn.androiddbdemo.greendao;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
@Entity
public class UserInfo {
@Id(autoincrement = true)
private Long id;//主鍵 Long型,可以通過@Id(autoincrement = true)設置自增長
private String name;
private String age;
@Generated(hash = 752529704)
public UserInfo(Long id, String name, String age) {
this.id = id;
this.name = name;
this.age = age;
}
@Generated(hash = 1279772520)
public UserInfo() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return this.age;
}
public void setAge(String age) {
this.age = age;
}
}
添加或刪除完實體類屬性後 將原本自動生成的構造方法以及getter/setter方法刪除,重新Build—>Make Project進行生成。
修改後的實體類
package com.wjn.androiddbdemo.greendao;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
@Entity
public class UserInfo {
@Id(autoincrement = true)
private Long id;//主鍵 Long型,可以通過@Id(autoincrement = true)設置自增長
private String name;
private String age;
private String describe;
@Generated(hash = 819903449)
public UserInfo(Long id, String name, String age, String describe) {
this.id = id;
this.name = name;
this.age = age;
this.describe = describe;
}
@Generated(hash = 1279772520)
public UserInfo() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return this.age;
}
public void setAge(String age) {
this.age = age;
}
public String getDescribe() {
return this.describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
}
即 添加了一個describe字段。
在表實體中,調整其中的變量(表字段),一般就是新增/刪除/修改字段。注意:
新增的字段或修改的字段,其變量類型應使用基礎數據類型的包裝類,如使用Integer而不是int,避免升級過程中報錯。
自定義DaoMaster.OpenHelper
package com.wjn.androiddbdemo.utils.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.wjn.androiddbdemo.greendao.DaoMaster;
import org.greenrobot.greendao.database.Database;
public class MyGreenDaoOpenHelper extends DaoMaster.OpenHelper {
/**
* 構造方法
* */
public MyGreenDaoOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
/**
* onUpgrade方法
* 將老表的數據複製到新表
* */
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
super.onUpgrade(db, oldVersion, newVersion);
//1.將舊錶改名成臨時表
String sql1 = "ALTER TABLE USER_INFO RENAME TO _USER_INFO";
//2.創建新表
String sql2=" CREATE TABLE USER_INFO (_id INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT,AGE TEXT,DESCRIBE TEXT);";
//3.將臨時表的數據導入到新表 原表中沒有的要自己設個默認值
String sql3="INSERT INTO USER_INFO SELECT _id,NAME,AGE,\"這是描述\" FROM _USER_INFO";
//刪除臨時表
String sql4="DROP TABLE _USER_INFO";
//執行SQL語句
db.execSQL(sql1);
db.execSQL(sql2);
db.execSQL(sql3);
db.execSQL(sql4);
}
}
注意:
這裏和SQLite數據庫升級一樣,要判斷版本問題(比如從版本1直接到版本3,中間沒有版本2的某個實體類)。詳見
修改程序入口初始化Helper類的方式
/**
* 配置數據庫
*/
private void setupDatabase() {
//創建數據庫shop.db 創建SQLite數據庫的SQLiteOpenHelper的具體實現
// DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "greendaodemo.db", null);
MyGreenDaoOpenHelper helper=new MyGreenDaoOpenHelper(this,"greendaodemo.db",null);
//獲取SQLiteDatabase對象
SQLiteDatabase db = helper.getReadableDatabase();
//獲取數據庫對象
DaoMaster daoMaster = new DaoMaster(db);
//獲取dao對象管理者
daoSession = daoMaster.newSession();
}
即
將
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "greendaodemo.db", null);
換成自定義的
MyGreenDaoOpenHelper helper=new MyGreenDaoOpenHelper(this,"greendaodemo.db",null);
然後再將版本從1——>2 再次查詢
package com.wjn.androiddbdemo.activity.greendao;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.wjn.androiddbdemo.MyApplication;
import com.wjn.androiddbdemo.R;
import com.wjn.androiddbdemo.greendao.UserInfo;
import com.wjn.androiddbdemo.greendao.UserInfoDao;
import com.wjn.androiddbdemo.utils.ui.StatusBarUtil;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.ArrayList;
import java.util.List;
public class GreenDaoUpdateActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView1;
private TextView textView2;
private TextView textView3;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_greendaoupdate);
initView();
}
/**
* 初始化各種View
*/
private void initView() {
//根據狀態欄顏色來決定 狀態欄背景 用黑色還是白色 true:是否修改狀態欄字體顏色
StatusBarUtil.setStatusBarMode(this, false, false, R.color.colorPrimary);
textView1 = findViewById(R.id.activity_greendaoupdate_textview1);
textView2 = findViewById(R.id.activity_greendaoupdate_textview2);
textView3 = findViewById(R.id.activity_greendaoupdate_textview3);
textView = findViewById(R.id.activity_greendaoupdate_textview);
textView1.setOnClickListener(this);
textView2.setOnClickListener(this);
textView3.setOnClickListener(this);
}
/**
* 各種點擊事件的方法
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_greendaoupdate_textview1://插入數據
insertUser();
break;
case R.id.activity_greendaoupdate_textview2://查詢數據
List<UserInfo> list=queryUserList();
StringBuilder sbBuilder = new StringBuilder();
for(int i=0;i<list.size();i++){
UserInfo userInfo=list.get(i);
Long id=userInfo.getId();
String name=userInfo.getName();
String age=userInfo.getAge();
sbBuilder.append("ID:" + id + "\n");
sbBuilder.append("姓名:" + name + "\n\n");
sbBuilder.append("年齡:" + age + "\n\n");
}
textView.setText(sbBuilder.toString());
break;
case R.id.activity_greendaoupdate_textview3://更新後查詢數據
List<UserInfo> lists=queryUserList();
StringBuilder sbBuilders = new StringBuilder();
for(int i=0;i<lists.size();i++){
UserInfo userInfo=lists.get(i);
Long id=userInfo.getId();
String name=userInfo.getName();
String age=userInfo.getAge();
String describe=userInfo.getDescribe();
sbBuilders.append("ID:" + id + "\n");
sbBuilders.append("姓名:" + name + "\n");
sbBuilders.append("年齡:" + age + "\n");
sbBuilders.append("描述:" + describe + "\n\n");
}
textView.setText(sbBuilders.toString());
break;
default:
break;
}
}
/**
* 插入多條條記錄
*/
public void insertUser() {
UserInfo userInfo=new UserInfo();
userInfo.setName("張三");
userInfo.setAge("29");
UserInfo userInfo1=new UserInfo();
userInfo1.setName("李四");
userInfo1.setAge("39");
UserInfo userInfo2=new UserInfo();
userInfo2.setName("旺旺");
userInfo2.setAge("19");
UserInfo userInfo3=new UserInfo();
userInfo3.setName("王偉");
userInfo3.setAge("59");
List<UserInfo> list=new ArrayList<>();
list.add(userInfo);
list.add(userInfo1);
list.add(userInfo2);
list.add(userInfo3);
UserInfoDao userInfoDao= MyApplication.getDaoInstant().getUserInfoDao();
userInfoDao.insertInTx(list);
}
/**
* 查詢數據列表 姓名=“張三”
*/
public List<UserInfo> queryUserList() {
UserInfoDao userInfoDao= MyApplication.getDaoInstant().getUserInfoDao();
QueryBuilder<UserInfo> qb = userInfoDao.queryBuilder();
List<UserInfo> list = qb.list();
return list;
}
}
結果
解決方案2:GitHub上的幫助類
Gradle添加依賴
根Gradle
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }//GreenDao數據庫升級
}
}
APP Gradle
//GreenDao數據庫升級
implementation 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.1.0'
幫助類
package com.wjn.androiddbdemo.utils.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.github.yuweiguocn.library.greendao.MigrationHelper;
import com.wjn.androiddbdemo.greendao.DaoMaster;
import com.wjn.androiddbdemo.greendao.UserInfoDao;
import org.greenrobot.greendao.database.Database;
public class MyGitHubGreenDaoOpenHelper extends DaoMaster.OpenHelper{
/**
* 構造方法
* */
public MyGitHubGreenDaoOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
/**
* onUpgrade方法
* 使用GitHub MigrationHelper 將老表的數據複製到新表
* */
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
super.onUpgrade(db, oldVersion, newVersion);
//把需要管理的數據庫表DAO作爲最後一個參數傳入到方法中
MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
@Override
public void onCreateAllTables(Database db, boolean ifNotExists) {
DaoMaster.createAllTables(db, ifNotExists);
}
@Override
public void onDropAllTables(Database db, boolean ifExists) {
DaoMaster.dropAllTables(db, ifExists);
}
}, UserInfoDao.class);
}
}
注意:
在表實體中,調整其中的變量(表字段),一般就是新增/刪除/修改字段。注意:
1)新增的字段或修改的字段,其變量類型應使用基礎數據類型的包裝類,如使用Integer而不是int,避免升級過程中報錯。
2)根據MigrationHelper中的代碼,升級後,新增的字段和修改的字段,都會默認被賦予null值。
APP入口替換
/**
* 配置數據庫
*/
private void setupDatabase() {
//創建數據庫shop.db 創建SQLite數據庫的SQLiteOpenHelper的具體實現
// DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "greendaodemo.db", null);
// MyGreenDaoOpenHelper helper=new MyGreenDaoOpenHelper(this,"greendaodemo.db",null);
MyGitHubGreenDaoOpenHelper helper=new MyGitHubGreenDaoOpenHelper(this,"greendaodemo.db",null);
//獲取SQLiteDatabase對象
SQLiteDatabase db = helper.getReadableDatabase();
//獲取數據庫對象
DaoMaster daoMaster = new DaoMaster(db);
//獲取dao對象管理者
daoSession = daoMaster.newSession();
}
實體類添加字段
將原本自動生成的構造方法以及getter/setter方法刪除,重新Build—>Make Project進行生成。
package com.wjn.androiddbdemo.greendao;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
@Entity
public class UserInfo {
@Id(autoincrement = true)
private Long id;//主鍵 Long型,可以通過@Id(autoincrement = true)設置自增長
private String name;
private String age;
private String githubdes;
@Generated(hash = 466573838)
public UserInfo(Long id, String name, String age, String githubdes) {
this.id = id;
this.name = name;
this.age = age;
this.githubdes = githubdes;
}
@Generated(hash = 1279772520)
public UserInfo() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return this.age;
}
public void setAge(String age) {
this.age = age;
}
public String getGithubdes() {
return this.githubdes;
}
public void setGithubdes(String githubdes) {
this.githubdes = githubdes;
}
}
然後再將版本從1——>2 再次查詢
package com.wjn.androiddbdemo.activity.greendao;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.wjn.androiddbdemo.MyApplication;
import com.wjn.androiddbdemo.R;
import com.wjn.androiddbdemo.greendao.UserInfo;
import com.wjn.androiddbdemo.greendao.UserInfoDao;
import com.wjn.androiddbdemo.utils.ui.StatusBarUtil;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.ArrayList;
import java.util.List;
public class GreenDaoUpdateActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView1;
private TextView textView2;
private TextView textView3;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_greendaoupdate);
initView();
}
/**
* 初始化各種View
*/
private void initView() {
//根據狀態欄顏色來決定 狀態欄背景 用黑色還是白色 true:是否修改狀態欄字體顏色
StatusBarUtil.setStatusBarMode(this, false, false, R.color.colorPrimary);
textView1 = findViewById(R.id.activity_greendaoupdate_textview1);
textView2 = findViewById(R.id.activity_greendaoupdate_textview2);
textView3 = findViewById(R.id.activity_greendaoupdate_textview3);
textView = findViewById(R.id.activity_greendaoupdate_textview);
textView1.setOnClickListener(this);
textView2.setOnClickListener(this);
textView3.setOnClickListener(this);
}
/**
* 各種點擊事件的方法
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_greendaoupdate_textview1://插入數據
insertUser();
break;
case R.id.activity_greendaoupdate_textview2://查詢數據
List<UserInfo> list=queryUserList();
StringBuilder sbBuilder = new StringBuilder();
for(int i=0;i<list.size();i++){
UserInfo userInfo=list.get(i);
Long id=userInfo.getId();
String name=userInfo.getName();
String age=userInfo.getAge();
sbBuilder.append("ID:" + id + "\n");
sbBuilder.append("姓名:" + name + "\n\n");
sbBuilder.append("年齡:" + age + "\n\n");
}
textView.setText(sbBuilder.toString());
break;
case R.id.activity_greendaoupdate_textview3://更新後查詢數據
List<UserInfo> lists=queryUserList();
StringBuilder sbBuilders = new StringBuilder();
for(int i=0;i<lists.size();i++){
UserInfo userInfo=lists.get(i);
Long id=userInfo.getId();
String name=userInfo.getName();
String age=userInfo.getAge();
String describe=userInfo.getGithubdes();
sbBuilders.append("ID:" + id + "\n");
sbBuilders.append("姓名:" + name + "\n");
sbBuilders.append("年齡:" + age + "\n");
sbBuilders.append("GitHub描述:" + describe + "\n\n");
}
textView.setText(sbBuilders.toString());
break;
default:
break;
}
}
/**
* 插入多條條記錄
*/
public void insertUser() {
UserInfo userInfo=new UserInfo();
userInfo.setName("張三");
userInfo.setAge("29");
UserInfo userInfo1=new UserInfo();
userInfo1.setName("李四");
userInfo1.setAge("39");
UserInfo userInfo2=new UserInfo();
userInfo2.setName("旺旺");
userInfo2.setAge("19");
UserInfo userInfo3=new UserInfo();
userInfo3.setName("王偉");
userInfo3.setAge("59");
List<UserInfo> list=new ArrayList<>();
list.add(userInfo);
list.add(userInfo1);
list.add(userInfo2);
list.add(userInfo3);
UserInfoDao userInfoDao= MyApplication.getDaoInstant().getUserInfoDao();
userInfoDao.insertInTx(list);
}
/**
* 查詢數據列表 姓名=“張三”
*/
public List<UserInfo> queryUserList() {
UserInfoDao userInfoDao= MyApplication.getDaoInstant().getUserInfoDao();
QueryBuilder<UserInfo> qb = userInfoDao.queryBuilder();
List<UserInfo> list = qb.list();
return list;
}
}
結果
MigrationHelper 源碼解析
由上可知 在onUpgrade方法中調用了MigrationHelper.migrate()方法
MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
@Override
public void onCreateAllTables(Database db, boolean ifNotExists) {
DaoMaster.createAllTables(db, ifNotExists);
}
@Override
public void onDropAllTables(Database db, boolean ifExists) {
DaoMaster.dropAllTables(db, ifExists);
}
}, UserInfoDao.class);
也就是說 升級數據庫的操作是在這個方法中。
public static void migrate(Database database, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {
weakListener = new WeakReference<>(listener);
migrate(database, daoClasses);
}
public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {
printLog("【Generate temp table】start");
generateTempTables(database, daoClasses);
printLog("【Generate temp table】complete");
ReCreateAllTableListener listener = null;
if (weakListener != null) {
listener = weakListener.get();
}
if (listener != null) {
listener.onDropAllTables(database, true);
printLog("【Drop all table by listener】");
listener.onCreateAllTables(database, false);
printLog("【Create all table by listener】");
} else {
dropAllTables(database, true, daoClasses);
createAllTables(database, false, daoClasses);
}
printLog("【Restore data】start");
restoreData(database, daoClasses);
printLog("【Restore data】complete");
}
private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
String tempTableName = null;
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
if (!isTableExists(db, false, tableName)) {
printLog("【New Table】" + tableName);
continue;
}
try {
tempTableName = daoConfig.tablename.concat("_TEMP");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");
db.execSQL(dropTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);
insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig));
printLog("【Generate temp table】" + tempTableName);
} catch (SQLException e) {
Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);
}
}
}
private static void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
if (!isTableExists(db, true, tempTableName)) {
continue;
}
try {
// get all columns from tempTable, take careful to use the columns list
List<TableInfo> newTableInfos = TableInfo.getTableInfo(db, tableName);
List<TableInfo> tempTableInfos = TableInfo.getTableInfo(db, tempTableName);
ArrayList<String> selectColumns = new ArrayList<>(newTableInfos.size());
ArrayList<String> intoColumns = new ArrayList<>(newTableInfos.size());
for (TableInfo tableInfo : tempTableInfos) {
if (newTableInfos.contains(tableInfo)) {
String column = '`' + tableInfo.name + '`';
intoColumns.add(column);
selectColumns.add(column);
}
}
// NOT NULL columns list
for (TableInfo tableInfo : newTableInfos) {
if (tableInfo.notnull && !tempTableInfos.contains(tableInfo)) {
String column = '`' + tableInfo.name + '`';
intoColumns.add(column);
String value;
if (tableInfo.dfltValue != null) {
value = "'" + tableInfo.dfltValue + "' AS ";
} else {
value = "'' AS ";
}
selectColumns.add(value + column);
}
}
if (intoColumns.size() != 0) {
StringBuilder insertTableStringBuilder = new 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(";");
db.execSQL(insertTableStringBuilder.toString());
printLog("【Restore data】 to " + tableName);
}
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(dropTableStringBuilder.toString());
printLog("【Drop temp table】" + tempTableName);
} catch (SQLException e) {
Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);
}
}
}
可以看出,其實它也是創建臨時表,然後創建新表,再將臨時表中數據拷貝到新表。最後刪除臨時表。
代碼鏈接:https://github.com/wujianning/AndroidDBDemo
附:
GitHub鏈接:
https://github.com/yuweiguocn/GreenDaoUpgradeHelper