greenDao架构升级

时间:2013-04-22 18:27:13

标签: android orm greendao

我已经看到了使用green dao(here

进行架构升级/迁移的另一个问题

在该答案中有许多链接可用于进行模式升级时使用的良好模式 - 但是没有关于您实际对数据执行的操作的示例,以便正确地迁移它并且我无法找到任何内容。

在我的情况下,我的迁移非常直接 - 我不希望转换任何现有数据,我只需要在我的架构中添加一些新表,我怀疑这是一种相当常见的情况。

在不删除用户已保存的数据的情况下,将新表添加到架构的最简单方法是什么?我们将非常感谢一个具体的例子。

如果greenDao提供了一个类似于DevOpenHelper的类,它会简单地添加以前不存在于模式中的新表/列,而不会先丢弃现有的tabes / data,这将是非常棒的。

4 个答案:

答案 0 :(得分:44)

我终于有时间深入了解这一点,并意识到在旧表中保留数据的同时添加新表非常容易。

免责声明:虽然我意识到这种实现特定于我的场景,但我认为对于像我这样使用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”是否是您要升级的那个,然后只调用“new”表的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 create语句并利用它们。

要向现有表(EXISTING_TABLE)添加单个新列(NEW_COLUMN,假设它是INTEGER类型),请执行以下操作:

db.execSQL("ALTER TABLE 'EXISTING_TABLE' ADD 'NEW_COLUMN' INTEGER");

对我来说,我需要做的就是添加新的表格,所以这最终变得相当直接。希望其他人认为这很有用。

答案 1 :(得分:9)

无论前一个用户来自哪里,我都采用了稍微不同的方法来自动处理更新。 首先,我创建了一个在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以获得一个看起来像这样的自定义

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


        }
    }
}

因此,如果您仔细命名您的Migration Helpers(即MigrationHelper5从架构5迁移到架构6),您可以实现此逻辑,然后在每个MigratorHelper类中,只需使用您需要的所有sql代码实现execSQL调用。实施

最后再说一句,如果你正在使用proguard,那么按类查找名称的方法可能不起作用,因为在混淆代码时会更改类名。您可能需要考虑在proguard配置文件(proguard-rules.pro)上添加一个例外,以排除从AbstractMigratorHelper扩展的任何类

# Avoid errors when upgrading database migrators

-keep public class * extends yourpackage.locationofyourclass.AbstractMigratorHelper

答案 2 :(得分:5)

我的方式略有不同。

我将新的@DatabaseTable类和任何@DatabaseFields添加到现有的@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);
        }

    }
}

答案 3 :(得分:0)

要回答@MBH在第一个答案上发布的问题。另外,我没有在这篇文章中找到答案,因此添加了。

GreenDAO使用build.gradle文件中的架构版本号。 Gradle文件应包含在

 "styles": [
     "node_modules/bootstrap/dist/css/bootstrap.min.css",
  ],
  "scripts": [
      "node_modules/jquery/dist/jquery.min.js",
      "node_modules/bootstrap/dist/js/bootstrap.js",
  ],

请参阅此link,以获取更多信息。然后在升级时将此数字更改为2或任何增量。基于该数字,GreenDAO在android.database.sqlite.SQLiteDatabase.DatabaseOpenHelper.java API下调用以下

android {
   ...
}
greendao {
   schemaVersion 1
}

作为Sqlite DB升级的标准方法,它在API下面进行调用

public DatabaseOpenHelper(Context context, String name, int version)

正如其他答案所建议的那样,可以在派生类中重写此方法,并且可以处理任何项目特定的升级。 希望这会有所帮助。