最近更新:2018年3月6日18:47:26
因为数据库添加字段,所以我就把 src中的schemaVersion +1,签完名之后测试,发现以前所有数据丢失了,顿时一身冷汗,太可怕了。之后在网上找资料发现DaoMaster中onUpgrade中 代码是:
dropAllTables(db, true); onCreate(db);所以每次升级,都是先把所有表都删了,重新创建,这怎么可以,侮辱Greendao,怎么这样设计,我升级数据库,你至少给我选择啊,到底是删除还是保留上一次数据。
没有办法,继续找资料,解决的办法无非是:把旧表改为临时表,建立新表,临时表数据写入新表,删除临时表。我又不是太懂数据库,懂思路是懂了,但是要怎么下手?好吧,继续找资料。
正题:
1.把MyApplication中初始化数据库 改成
DaoMaster.DevOpenHelper mHelper = new MigrationHelper(this, "mydatabase.db", null);
2.编写 MigrationHelper类
public class MigrationHelper extends DaoMaster.DevOpenHelper { private final String TAG="MigrationHelper"; public MigrationHelper(Context context, String name) { super(context, name); } public MigrationHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { LogUtil.i(TAG,"oldVersion="+oldVersion+",newVersion="+newVersion); if (newVersion > oldVersion) { new UpgradeHelper().migrate(db, AdcDao.class, .......... SettingDao.class, WifiDao.class); } } }....表示你所有的表。
3.编写 UpgradeHelper 类
public class UpgradeHelper { private final String TAG = "UpgradeHelper"; private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS"; private static MigrationHelper instance; public static MigrationHelper getInstance() { if (instance == null) { instance = new MigrationHelper(MyApplacition.getInstances(), "mydatabase.db"); } return instance; } public void migrate(final Database db, final Class<? extends AbstractDao<?, ?>>... daoClasses) { LogUtil.i(TAG, "1111"); generateTempTables(db, daoClasses); LogUtil.i(TAG, "2222"); DaoMaster.dropAllTables(db, true); LogUtil.i(TAG, "3333"); DaoMaster.createAllTables(db, false); LogUtil.i(TAG, "4444"); restoreData(db, daoClasses); } private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { try { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String divider = ""; String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); ArrayList<String> properties = new ArrayList<>(); StringBuilder createTableStringBuilder = new StringBuilder(); createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" ("); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (getColumns(db, tableName).contains(columnName)) { properties.add(columnName); String type = null; try { type = getTypeByClass(daoConfig.properties[j].type); } catch (Exception exception) { exception.printStackTrace(); } createTableStringBuilder.append(divider).append(columnName).append(" ").append(type); if (daoConfig.properties[j].primaryKey) { createTableStringBuilder.append(" PRIMARY KEY"); } divider = ","; } } createTableStringBuilder.append(");"); db.execSQL(createTableStringBuilder.toString()); StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); } catch (Exception e) { e.printStackTrace(); } finally { continue; } } } private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { try { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); LogUtil.i(TAG, "tableName=" + tableName); ArrayList<String> properties = new ArrayList(); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (getColumns(db, tempTableName).contains(columnName)) { properties.add(columnName); } } StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); db.execSQL(insertTableStringBuilder.toString()); db.execSQL(dropTableStringBuilder.toString()); } catch (Exception e) { e.printStackTrace(); } finally { continue; } } }
private String getTypeByClass(Class<?> type) throws Exception { if (type.equals(String.class)) { return "TEXT"; } if (type.equals(Long.class) || type.equals(long.class)|| type.equals(Integer.class) || type.equals(int.class)|| type.equals(byte.class)||type.equals(Byte.class)|| type.equals(short.class)||type.equals(Short.class)) { return "INTEGER"; } if (type.equals(Boolean.class)||type.equals(boolean.class)) { return "BOOLEAN"; } if (type.equals(Double.class)||type.equals(double.class) ||type.equals(float.class)||type.equals(Float.class)){ return "REAL"; } if(type.equals(byte[].class)){ return "BLOB"; } Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString())); exception.printStackTrace(); throw exception; }
private static List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
你再试一试,发现是不是可以了,哦记住schemaVersion 要加1。
我试过 增加字段和 添加表 都是可以的,删除我没有试过。
注意:getTypeByClass中一定注意写好对应的数据类型,这个跟SQL不一样,你看我的,我写了一部分,但是你自己操作比较好,我告诉你方法。在DaoMaster中找到creatAllTable方法,有多少个表就有多少类似xxxDao.creatTable(db,ifNotExists)。进入createTable可以看到
db.execSQL("CREATE TABLE " + constraint + "\"BUS_EVENT__REPORT\" (" + // "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id "\"mode\" INTEGER NOT NULL ," + // 1: mode "\"tel\" TEXT," + // 2: tel
这里你就可以看到 叫mode的字段是INTERGET 叫tel的字段类型是TEXT。
所以在getTypeByClass中也模仿着写,你懂了吧。
OK!