GreenDao 3.x 数据库版本升级 迁移数据

网上搜索很多都是3.0以下的版本数据迁移配置,在此记录自己3.2.2版本的数据迁移的配置

1.修改之前的数据迁移类

public class MigrationHelper {
  
private static MigrationHelper instance;

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

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

private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
    for(int i = 0; i < daoClasses.length; i++) {
        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) {
                    Log.e(TAG,exception.toString());
                }

                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());
    }
}

private 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");
        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());
    }
}

private String getTypeByClass(Class<?> type) throws Exception {
    if(type.equals(String.class)) {
        return "TEXT";
    }
    if(type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
        return "INTEGER";
    }
    if(type.equals(Boolean.class)) {
        return "BOOLEAN";
    }

    Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
    Log.e(TAG,exception.toString());
    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;
 }
}

2.创建一个类继承 DaoMaster.OpenHelper

public class UpdateOpenHelper extends DaoMaster.OpenHelper {


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

public UpdateOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
    super(context, name, factory);
}

//此方法用于3.0版本之前的升级方案 须将MigrationHelper中的DB 类型更改为SQLiteDatabase
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    super.onUpgrade(db, oldVersion, newVersion);
    if (oldVersion < newVersion) {
        Log.i("version", oldVersion + "---先前和更新之后的版本---" + newVersion);
        //            MigrationHelper.getInstance().migrate(db, UserDao.class);
        //更改过的实体类(新增的不用加)   更新UserDao文件 可以添加多个  XXDao.class 文件
        //             MigrationHelper.getInstance().migrate(db, UserDao.class,XXDao.class);
    }
}


@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
    super.onUpgrade(db, oldVersion, newVersion);
    Log.i("version", oldVersion + "---先前和更新之后的版本---" + newVersion);
    if (oldVersion < newVersion) {
        MigrationHelper.getInstance().migrate(db, UserDao.class);
        //更改过的实体类(新增的不用加)   更新UserDao文件 可以添加多个  XXDao.class 文件
      //MigrationHelper.getInstance().migrate(db, UserDao.class, XXDao.class);
  }
 }
}

3.修改GreenDao的初始化

修改前的初始化
    mHelper = new DaoMaster.DevOpenHelper(this, "test-db.db", null);
    db = mHelper.getWritableDatabase();
    // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
    mDaoMaster = new DaoMaster(db);
    mDaoSession = mDaoMaster.newSession();
    //获取对应的数据库表对象
    userDao = mDaoSession.getUserDao();
修改后
    mHelper = new UpdateOpenHelper(this, "test-db.db", null);
    db = mHelper.getWritableDatabase();
    // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
    mDaoMaster = new DaoMaster(db);
    mDaoSession = mDaoMaster.newSession();
    //获取对应的数据库表对象
    userDao = mDaoSession.getUserDao();
我的DB管理类
public class DBManager {
// 是否加密
public static final boolean ENCRYPTED = true;

private static final String DB_NAME = "test-db.db";
private static DbManager mDbManager;
private static DaoMaster.DevOpenHelper mDevOpenHelper;
private static DaoMaster mDaoMaster;
private static DaoSession mDaoSession;

private Context mContext;

private DBManager(Context context) {
    this.mContext = context;
    // 初始化数据库信息
    mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);
    getDaoMaster(context);
    getDaoSession(context);
}

public static DBManager getInstance(Context context) {
    if (null == mDBManager) {
        synchronized (DBManager.class) {
            if (null == mDBManager) {
                mDBManager = new DBManager(context);
            }
        }
    }
    return mDBManager;
}

/**
 * 获取可读数据库
 *
 * @param context
 * @return
 */
public static SQLiteDatabase getReadableDatabase(Context context) {
    if (null == mDevOpenHelper) {
        getInstance(context);
    }
    return mDevOpenHelper.getReadableDatabase();
}

/**
 * 获取可写数据库
 *
 * @param context
 * @return
 */
public static SQLiteDatabase getWritableDatabase(Context context) {
    if (null == mDevOpenHelper) {
        getInstance(context);
    }
    return mDevOpenHelper.getWritableDatabase();
}

/**
 * 获取DaoMaster
 *
 * 判断是否存在数据库,如果没有则创建数据库
 * @param context
 * @return
 */
public static DaoMaster getDaoMaster(Context context) {
    if (null == mDaoMaster) {
        synchronized (DbManager.class) {
            if (null == mDaoMaster) {
                UpdateOpenHelper helper = new UpdateOpenHelper(context,DB_NAME,null);
                mDaoMaster = new DaoMaster(helper.getWritableDatabase());
            }
        }
    }
    return mDaoMaster;
}

/**
 * 未添加版本更新前的获取方法
 * 获取DaoMaster
 *
 * @param context
 * @return
 */
//    public static DaoMaster getDaoMaster(Context context) {
//        if (null == mDaoMaster) {
//            synchronized (DbManager.class) {
//                if (null == mDaoMaster) {
//
//                    mDaoMaster = new DaoMaster(getWritableDatabase(context));
//                }
//            }
//        }
//        return mDaoMaster;
//    }

/**
 * 获取DaoSession
 *
 * @param context
 * @return
 */
public static DaoSession getDaoSession(Context context) {
    if (null == mDaoSession) {
        synchronized (DbManager.class) {
            mDaoSession = getDaoMaster(context).newSession();
        }
    }

    return mDaoSession;
 }
}

4.注意事项

实体类中新增字段,必须为Long,Double,Integer,Float,String类型,否则在数据迁移时会出现空指针异常

你可以查看对应的Dao类中createTable()方法 double等类型会在字段后出现REAL NOT NULL

   /** Creates the underlying database table. */
   public static void createTable(Database db, boolean ifNotExists) {
    String constraint = ifNotExists? "IF NOT EXISTS ": "";
    db.execSQL("CREATE TABLE " + constraint + "\"USER\" (" + //
            "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
            "\"NAME\" TEXT," + // 1: name
            "\"PASSWORD\" TEXT," + // 2: password
            "\"AGE\" TEXT," + // 3: age
            "\"A\" REAL NOT NULL );"); // 4: a   为double类型
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容