您的位置:首页 > 数据库

Greendao 数据库升级解决方案

2016-08-31 11:27 246 查看
APP开发期间的数据库改动(APP未上线)

直接上DaoMaster的代码

/*** WARNING: Drops all table on Upgrade! Use only during development. */

public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}


注意看第一行注释:WARNING: Drops all table on Upgrade! Use only during development.

数据库升级的话,会删除所有表,然后重新创建。这种方式在开发期间,APP还没有上线之前是可以的。

当APP上线后,我们不能使用这种方式,因为这样会导致已经存在的数据会被删除。

2.APP上线后,数据库升级

需要我们写一个类来实现OpenHelper

1.我们自己实现了onUpgrade 方法来自定义升级过程。

2.当然升级过程中也要修改DaoMaster.SCHEMA_VERSION

3.当DaoMaster.SCHEMA_VERSION 跟你当前数据库的版本比较后, 会根据你当前数据库的版本,然后进行升级。

4.关键代码onUpgrade 方法,会比较新数据库和旧数据库的版本,然后执行相应的sql升级:

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
LogUtil.w(SQLiteOpenHelper.class.getSimpleName(), "Upgrade from" + oldVersion + "to" + newVersion);
SortedMap<Integer, Migration> migrations = ALL_MIGRATIONS.subMap(oldVersion, newVersion);
executeMigrations(sqLiteDatabase, migrations.keySet());
}

private void executeMigrations(final SQLiteDatabase paramSQLiteDatabase, final Set<Integer> migrationVersions) {
for (final Integer version : migrationVersions) {
ALL_MIGRATIONS.get(version).migrate(paramSQLiteDatabase);
}
}


最后,推荐一个国外大神封装的Greendao上线后数据库升级的工具类

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.database.Database;
import de.greenrobot.dao.database.StandardDatabase;
import de.greenrobot.dao.internal.DaoConfig;

/**
* Createdby PedroOkawa and modified by MBH on 16/08/16.
*/
public final class MigrationHelper {

public static void migrate(SQLiteDatabase sqliteDatabase, Class<? extends AbstractDao<?, ?>>... daoClasses) {
StandardDatabase db = new StandardDatabase(sqliteDatabase);
generateNewTablesIfNotExists(db, daoClasses);
generateTempTables(db, daoClasses);
dropAllTables(db, true, daoClasses);
createAllTables(db, false, daoClasses);
restoreData(db, daoClasses);
}

public static void migrate(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateNewTablesIfNotExists(db, daoClasses);
generateTempTables(db, daoClasses);
dropAllTables(db, true, daoClasses);
createAllTables(db, false, daoClasses);
restoreData(db, daoClasses);
}

private static void generateNewTablesIfNotExists(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
reflectMethod(db, "createTable", true, daoClasses);
}

private static void generateTempTables(StandardDatabase 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");
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("CREATE TEMP TABLE ").append(tempTableName);
insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}

private static void dropAllTables(StandardDatabase db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
reflectMethod(db, "dropTable", ifExists, daoClasses);
}

private static void createAllTables(StandardDatabase db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
reflectMethod(db, "createTable", ifNotExists, daoClasses);
}

/**
* dao class already define the sql exec method, so just invoke it
*/
private static void reflectMethod(StandardDatabase db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
if (daoClasses.length < 1) {
return;
}
try {
for (Class cls : daoClasses) {
Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
method.invoke(null, db, isExists);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

private static void restoreData(StandardDatabase 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");
// get all columns from tempTable, take careful to use the columns list
List<String> columns = getColumns(db, tempTableName);
ArrayList<String> properties = new ArrayList<>(columns.size());
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (columns.contains(columnName)) {
properties.add(columnName);
}
}
if (properties.size() > 0) {
final String columnSQL = TextUtils.join(",", properties);

StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(columnSQL);
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(columnSQL);
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(dropTableStringBuilder.toString());
}
}

private static List<String> getColumns(StandardDatabase db, String tableName) {
List<String> columns = null;
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
if (null != cursor && cursor.getColumnCount() > 0) {
columns = Arrays.asList(cursor.getColumnNames());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
if (null == columns)
columns = new ArrayList<>();
}
return columns;
}

}


用法是这样

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
MigrationHelper.migrate(new StandardDatabase(sqLiteDatabase),
UserDao.class,
ItemDao.class);
// OR you can use it like this (Dont use both it is example of 2 different usages)
MigrationHelper.migrate(sqLiteDatabase,
UserDao.class,
ItemDao.class);
}


StandardDatabase 可以在greendao里面导入。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息