2013-04-22 68 views
24

我已经看到了使用绿道约架构升级/迁移另一个问题(heregreenDao模式升级

有很多在回答环节的良好格局做模式升级时使用 - 但有没有例子你实际上对你的数据做了什么来正确地迁移它,我无法找到任何东西。在我的情况下,我的迁移非常简单 - 我不希望转换任何现有的数据,我只需要在我的模式中添加一些新表,我怀疑这是一个相当常见的情况。

将新表格添加到模式而不删除用户已保存的数据的最简单方法是什么?一个具体的例子将不胜感激。

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

回答

40

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

免责声明:当我意识到这一点的实现是具体到我的情况,我认为这是有帮助的对像我这样谁使用的是Android ORM工具(greenDao)专门对付Android上的SQLite。我知道这对于那些从一开始就编写了自己的表创建查询的人来说是非常常见的,但对于那些不熟悉使用Android的SQLite DB的人来说,我认为这个例子会很有帮助。

答案: 您可以修改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); 
} 

不是丢弃所有表,看看该createAllTables方法是自动生成的GreenDao。

重写onUpgrade以检查“oldVersion”是否是您要升级的“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或看看自动生成的SQL创建greenDao和杠杆声明那些。

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

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

对于我来说,现在,所有我需要做的是添加新的表格,所以这最终是相当直接的。希望别人认为这很有用。

+0

这是一个简单但很好的解决方案 – 2014-01-13 21:59:27

+2

你救了我一天的任何类,谢谢! – Ale 2016-06-16 15:25:53

+1

我们在哪里设置新版本号? – MBH 2016-07-27 14:50:42

5

我这样做的方式稍有不同。

我将新的@DatabaseTable类和任何@DatabaseField添加到现有的@DatabaseTable类并运行DatabaseConfigUtil。

然后,我将添加一个新的方法,以我的DatabaseUpgrader类,并修改我的DatabaseHelper,改变DATABASE_VERSION值和的o​​nUpdate方法

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

    } 
} 
+1

伟大的东西@RobCroll,我喜欢从我的方法是,无论您有多少迁移,您都不必更改升级方法上的代码。你只需要与clases的名称一致,对我来说这不是很难,因为通常我复制现有的Migration类来创建新的。你们的好处是,你们只有一个班级可以进行所有的迁徙,但是如果你们做了很多迁徙,班上的班级可能会很长 – pleonasmik 2014-09-24 15:02:24

8

我使用稍微不同的方法来自动处理更新,而不管前一位用户来自哪里。 首先,我创建了一个实现方法onUpgrade上SQLDatabase

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