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

2017-12-27  本文已影响0人  腐化的木头

网上搜索很多都是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类型
    }
上一篇下一篇

猜你喜欢

热点阅读