GreenDao3.0数据库升级保留原始数据的解决方法

/**
 * 数据库管理工具
 */
public class DBManager {
    private DaoMaster.DevOpenHelper devOpenHelper;
    private static DBManager instance;
    private static final String DB_NAME = "test.db";

    private DBManager() {
        devOpenHelper = new DBOpenHelper(MyApplication.getInstance(), DB_NAME);
    }

    public static DBManager getInstance() {
        if (instance == null) {
            instance = new DBManager();
        }
        return instance;
    }

    public SQLiteDatabase getWritableDatabase() {
        if (devOpenHelper == null) {
            devOpenHelper = new DBOpenHelper(MyApplication.getInstance(), DB_NAME);
        }
        SQLiteDatabase db = devOpenHelper.getWritableDatabase();
        return db;
    }

}

/**
 * 实现GreenDao数据库升级保留原始交易数据
 */
public class DBMigrationHelper {
    private static final String TAG = "DBMigrationHelper";

    //DB中约束为NOT NULL的数据类型
    List<Class> notNullClasses = Arrays.<Class>asList(boolean.class, byte.class, char.class,
            short.class, int.class, long.class, float.class, double.class,
            Boolean.class, Byte.class, Character.class, Short.class, Integer.class, Long.class,
            Float.class, Double.class);

    private Database db;
    private Collection<AbstractDao<?, ?>> allDaos;

    public DBMigrationHelper(SQLiteDatabase database) {
        db = new StandardDatabase(database);
        DaoMaster master = new DaoMaster(database);
        DaoSession session = master.newSession(IdentityScopeType.None);
        allDaos = session.getAllDaos();
    }

    /** 更改表结构,将旧表数据导入新表 */
    public void upgradeTablesScheme() {
        for (AbstractDao<?, ?> dao : allDaos) {
            @SuppressWarnings("unchecked")
            Class<? extends AbstractDao<?, ?>> daoCls = (Class<? extends AbstractDao<?, ?>>) dao.getClass();
            handleUpgradeTableScheme(db, daoCls);
        }
    }

    /** 删除临时表 */
    public void dropTempTables() {
        for (AbstractDao<?, ?> dao : allDaos) {
            @SuppressWarnings("unchecked")
            Class<? extends AbstractDao<?, ?>> daoCls = (Class<? extends AbstractDao<?, ?>>) dao.getClass();
            dropTempTable(db, daoCls);
        }
    }

    /** 执行表结构变更 */
    private void handleUpgradeTableScheme(Database db, Class<? extends AbstractDao<?, ?>> daoCls) {
        DaoConfig daoConfig = new DaoConfig(db, daoCls);
        String tableName = daoConfig.tablename;
        String tempTableName = tableName + "_TEMP";
        //重命名表
        db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tempTableName);
        //创建新表
        createTable(daoCls, db, true);

        List<String> oldColumns = getColumns(db, tempTableName);
        List<String> shareColumns = new ArrayList<>();
        List<String> newNotNullColumns = new ArrayList<>();
        for (Property property : daoConfig.properties) {
            if (oldColumns.contains(property.columnName)) {
                shareColumns.add(property.columnName);
            } else if (checkNotNull(property)) {
                newNotNullColumns.add(property.columnName);
            }
        }

        //将旧表数据导入新表
        String insertSQL = "INSERT INTO " + tableName + "("
                + TextUtils.join(",", shareColumns);
        if (!newNotNullColumns.isEmpty()) {
            insertSQL += ",";
            insertSQL += TextUtils.join(",", newNotNullColumns);
        }
        insertSQL += ") SELECT ";
        insertSQL += TextUtils.join(",", shareColumns);

        String notNullStr = "";
        for (String column : newNotNullColumns) {
            notNullStr += ",0 AS " + column;
        }
        insertSQL += notNullStr;
        insertSQL += " FROM " + tempTableName;

        db.execSQL(insertSQL);
    }

    /** 是否是非空列 */
    private boolean checkNotNull(Property property) {
        return notNullClasses.contains(property.type);
    }

    /** 删除旧表 */
    private void dropTempTable(Database db, Class<? extends AbstractDao<?, ?>> daoCls) {
        DaoConfig daoConfig = new DaoConfig(db, daoCls);
        String tableName = daoConfig.tablename;
        String tempTableName = tableName + "_TEMP";
        //删除旧表
        db.execSQL("DROP TABLE " + tempTableName);
    }

    /** 获取数据库所有列名称 */
    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) {
                Collections.addAll(columns, cursor.getColumnNames());
            }
        } catch (Exception e) {
            Log.v(tableName, e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return columns;
    }

    /** 创建表 */
    private static void createTable(Class<? extends AbstractDao<?, ?>> daoCls, Database db, boolean b) {
        reflectMethod(daoCls, "createTable", db, b);
    }

    /**
     * 反射createTable或dropTable方法
     */
    private static void reflectMethod(@NonNull Class<? extends AbstractDao<?, ?>> daoCls,
                                      String methodName, Database db, boolean isExists) {
        try {
            Method method = daoCls.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();
        }
    }


    /** 数据库升级接口,自定义升级时可实现本接口 */
    public interface IDBMigration {

        void onMigrate(SQLiteDatabase db);
    }

    /**
     * <pre>
     * V35版本数据库升级类,升级内容如下:
     * </pre>
     */
    public static class DBMigration_35 implements IDBMigration {
        @Override
        public void onMigrate(SQLiteDatabase db) {
            Database database = new StandardDatabase(db);
            //TODO   具体实现
        }
    }

    /**
     * <pre>
     * V40版本数据库升级类,升级内容如下:
     * </pre>
     */
    public static class DBMigration_40 implements IDBMigration {
        @Override
        public void onMigrate(SQLiteDatabase db) {
            //TODO  具体实现
        }
    }
}


/**
 * 数据库帮助类,重写了数据库升级操作,不删表保留原交易数据
 */
public class DBOpenHelper extends DaoMaster.DevOpenHelper {
    private static final String TAG = "DBOpenHelper";

    public DBOpenHelper(Context context, String name) {
        super(context, name);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        DaoMaster.createAllTables(new StandardDatabase(db), false);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            if (newVersion > oldVersion) {
                //更改表结构
                DBMigrationHelper helper = new DBMigrationHelper(db);
                helper.upgradeTablesScheme();

                for (int i = oldVersion + 1; i <= newVersion; i++) {
                    //获取不同数据库版本对应的迁移方法
                    //当用户跨版本升级时,依次执行每个版本对应的升级方法
                    Method method = getMigrationMethod(i);
                    if (method != null) {
                        method.invoke(this, db);
                    }
                }

                //删除临时表
                helper.dropTempTables();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "DB onUpgrade failed:" + e.getMessage());
        }
    }

    /**
     * 获取数据库版本对应的迁移方法
     * 数据库迁移方法命名格式为 migration_Scheme,其中
     * Scheme为每个数据库版本的版本号
     */
    private Method getMigrationMethod(int version) {
        try {
            return getClass().getDeclaredMethod("migration_" + version, SQLiteDatabase.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    /** V35版本数据库升级 */
    @SuppressWarnings("unused")
    private void migration_35(SQLiteDatabase db) {
        IDBMigration migration = new DBMigration_35();
        migration.onMigrate(db);
    }

    /** V40版本数据库升级 */
    @SuppressWarnings("unused")
    private void migration_40(SQLiteDatabase db) {
        IDBMigration migration = new DBMigration_40();
        migration.onMigrate(db);
    }
}

 

转载于:https://my.oschina.net/547217475/blog/1498854

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值