我看到另一个关于使用green dao升级/迁移模式的问题(这里)
在做模式升级时,有很多链接的答案,一个好的模式使用-但是没有什么例子,你实际做你的数据正确迁移它,我有困难找到任何东西。
在我的例子中,我的迁移非常直接——我不希望转换任何现有数据,我只需要向我的模式添加一些新表,我认为这是相当常见的情况。
在不删除用户已经保存的数据的情况下向模式添加新表的最简单方法是什么?
如果greenDao提供一个类似于DevOpenHelper的类,它可以简单地添加以前不存在于模式中的新表/列,而不需要先删除现有的表/数据,那就太棒了。
我终于有时间自己深入研究这个问题,并意识到在保留旧表中的数据的同时添加一个新表是很容易的。
免责声明:虽然我意识到这个实现是特定于我的场景,但我认为它对像我这样使用Android ORM工具(greenDao)专门处理Android上的SQLite的人很有帮助。我知道这对于那些从一开始就编写自己的表创建查询的人来说是很常见的,但是对于那些在Android上使用SQLite数据库的人来说,我认为这个例子会很有帮助。
答:您既可以修改DevOpenHelper内部类,也可以创建自己的类。我选择编辑DevOpenHelper暂时保持我的示例简单—但是,请注意,如果您重新生成greendao类,DevOpenHelper将被覆盖。这将是一个更好的主意,创建自己的类,如"MyOpenHelper",并使用它来代替。
在我改变之前,DevOpenHelper。onUpgrade看起来像这样:
@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);
}
与其删除所有表,不如看看GreenDao自动生成的createAllTables方法。
重写onUpgrade来检查"oldVersion"是否是你想要升级的,然后只调用"新"表的createTable方法。下面是我的onUpgrade方法现在的样子:
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " +
//Going from older schema to new schema
if(oldVersion == 3 && newVersion == 4)
{
boolean ifNotExists = false;
//Leave old tables alone and only create ones that didn't exist
//in the previous schema
NewTable1Dao.createTable(db, ifNotExists);
NewTable2Dao.createTable(db, ifNotExists);
NewTable3Dao.createTable(db, ifNotExists);
NewTable4Dao.createTable(db, ifNotExists);
}
else
{
dropAllTables(db, true);
onCreate(db);
}
}
添加一个新列将是类似的,除了您必须编写一些SQL或查看从greenDao自动生成的SQL创建语句并利用它们。
要向现有表(EXISTING_TABLE)添加单个新列(NEW_COLUMN,假设它是INTEGER类型),请执行以下操作:
db.execSQL("ALTER TABLE 'EXISTING_TABLE' ADD 'NEW_COLUMN' INTEGER");
对于我来说,现在我所需要做的就是添加新的表,所以这最终是相当直接的。希望有人觉得这有用。
我采用了一种稍微不同的方法来自动处理更新,无论以前的用户来自哪里。首先,我创建了一个类,它在SQLDatabase
上实现了onUpgrade方法public abstract class AbstractMigratorHelper {
public abstract void onUpgrade(SQLiteDatabase db);
}
将从这个类继承所有我将在后面声明的迁移器帮助器
我将写一个例子
public class DBMigrationHelper5 extends AbstractMigratorHelper {
/* Upgrade from DB schema x to schema x+1 */
public void onUpgrade(SQLiteDatabase db) {
//Example sql statement
db.execSQL("ALTER TABLE user ADD COLUMN USERNAME TEXT");
}
}
在此之后,您需要在升级时实际调用的类上实现逻辑,其中您需要删除以前的DevOpenHelper,以使用自定义的DevOpenHelper,如下所示
public static class UpgradeHelper extends OpenHelper {
public UpgradeHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
/**
* Here is where the calls to upgrade are executed
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
/* i represent the version where the user is now and the class named with this number implies that is upgrading from i to i++ schema */
for (int i = oldVersion; i < newVersion; i++) {
try {
/* New instance of the class that migrates from i version to i++ version named DBMigratorHelper{version that the db has on this moment} */
AbstractMigratorHelper migratorHelper = (AbstractMigratorHelper) Class.forName("com.nameofyourpackage.persistence.MigrationHelpers.DBMigrationHelper" + i).newInstance();
if (migratorHelper != null) {
/* Upgrade de db */
migratorHelper.onUpgrade(db);
}
} catch (ClassNotFoundException | ClassCastException | IllegalAccessException | InstantiationException e) {
Log.e(TAG, "Could not migrate from schema from schema: " + i + " to " + i++);
/* If something fail prevent the DB to be updated to future version if the previous version has not been upgraded successfully */
break;
}
}
}
}
因此,如果你小心地命名你的迁移助手(即MigrationHelper5从模式5迁移到模式6),你可以实现这个逻辑,然后在每个MigratorHelper类中实现execSQL调用与你需要实现的所有sql代码。
最后还有一点需要注意的是,如果您正在使用proguard,那么按类查找名称的方法可能不起作用,因为在混淆代码时类名称会发生变化。您可能需要考虑在proguard配置文件(proguard-rules.pro)中添加一个异常,以排除从AbstractMigratorHelper
扩展的任何类。# Avoid errors when upgrading database migrators
-keep public class * extends yourpackage.locationofyourclass.AbstractMigratorHelper
我的做法略有不同。
我添加我的新的@DatabaseTable类和任何@DatabaseTable字段到现有的@DatabaseTable类和运行DatabaseConfigUtil。
然后我将添加一个新方法到我的DatabaseUpgrader类和修改我的DatabaseHelper,改变DATABASE_VERSION值和onUpdate方法
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final int DATABASE_VERSION = 3;
@Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
switch (oldVersion) {
case 1:
DatabaseUpdater.from1to2(connectionSource);
DatabaseUpdater.from2to3(connectionSource);
break;
case 2:
DatabaseUpdater.from2to3(connectionSource);
break;
default:
onCreate(db);
}
}
}
public static DatabaseHelper getInstance() {
return DatabaseHelper.mHelper;
}
public static void setInstance(Context context) {
DatabaseHelper.mHelper = new DatabaseHelper(context);
}
…
}
然后在DatabaseUpdater类中
public class DatabaseUpdater {
private static final String TAG = "DatabaseHelper";
public static void from1to2(ConnectionSource connectionSource) {
try {
DatabaseHelper helper = DatabaseHelper.getInstance();
//Example add a table
TableUtils.createTable(connectionSource, AnotherEntity.class);
} catch (SQLException e) {
Log.e(TAG, "Error upgrading database to v2: ", e);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
public static void from2to3(ConnectionSource connectionSource) {
try {
DatabaseHelper helper = DatabaseHelper.getInstance();
//Example add a field to a table
RuntimeExceptionDao<MyEntity, Integer> myDao = helper.getMyDao();
diaryDao.executeRaw("ALTER TABLE myEntity ADD firstNewField");
diaryDao.executeRaw("ALTER TABLE myEntity ADD anotherNewField");
} catch (SQLException e) {
Log.e(TAG, "Error upgrading database to v3: ", e);
}
}
}
回答@MBH在第一个答案上发布的问题。我也没有在这篇文章中找到答案,因此添加。
GreenDAO使用构建中的模式版本号。gradle文件。Gradle文件应该包含以下内容
android {
...
}
greendao {
schemaVersion 1
}
有关更多信息,请参阅此链接。然后在升级时将此数字更改为2或任意增量。基于这个数字,GreenDAO从android.database.sqlite. sqliteddatabase . databaseopenhelper .java调用下面的API
public DatabaseOpenHelper(Context context, String name, int version)
作为Sqlite数据库升级的标准方法,它调用以下API
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
正如其他答案所建议的那样,该方法可以在派生类中被重写,并且可以处理任何特定于项目的升级。