我实际上正在开发一个使用ORMLite库的应用程序(这很棒btw),但我是初学者使用它。
我对设备内部数据库的更新有疑问。
假设有人在Google Play上下载了我的应用。几个月后,我肯定会在一些表中填入新的条目。
当此人正在对应用程序进行更新时,如何使用我的新条目更新数据库并将旧条目保留在其中。
更清楚一点,想象一下用户在我的应用中回答了问题。当我将介绍新问题时,如何在更新我的应用程序并保留已经回答的问题时将其插入数据库中?
答案 0 :(得分:33)
当此人正在对应用程序进行更新时,如何使用我的新条目更新数据库并将旧条目保留在其中。
我们的想法是使用传递给onUpgrade(...)
方法的版本号。使用ORMLite时,OrmLiteSqliteOpenHelper.onUpgrade(...)
方法会使用oldVersion
和newVersion
个数字。然后,您可以将转换代码编写到您的应用程序中,该代码能够转换旧格式的数据并更新架构。
有关详细信息,请参阅有关该主题的ORMLite文档:
要引用,您可以执行以下操作:
if (oldVersion < 2) {
// we added the age column in version 2
dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
}
if (oldVersion < 3) {
// we added the weight column in version 3
dao.executeRaw("ALTER TABLE `account` ADD COLUMN weight INTEGER;");
}
如果您有需要转换的现有数据,那么您应该尽可能在SQL中进行转换。
另一种选择是让Account
实体和OldAccount
实体指向同一个表名。然后,您可以使用OldAccount
读取oldAccountDao
个实体,将它们转换为Account
个实体,然后使用accountDao
将它们更新回同一个表格。你需要注意这里的对象缓存。
答案 1 :(得分:7)
我是这样做的:
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
updateFromVersion1(database, connectionSource, oldVersion, newVersion);
break;
case 2:
updateFromVersion2(database, connectionSource, oldVersion, newVersion);
break;
default:
// no updates needed
break;
}
}
private void updateFromVersion1(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
// do some stuff here
onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
}
private void updateFromVersion2(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
// do some stuff here
onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
}
这将逐步更新用户db,而不管他将来自哪个db版本。
答案 2 :(得分:3)
信息很少,目前尚不清楚您是否有表结构的变化。
a)如果您不更改数据库结构。
1在您的程序的新版本中,当您开始检查以前保存的版本时(例如,在首选项中) 使用当前(请参阅PackageManager.getPackageInfo)
saved = 0 - 用户刚刚安装了新版本
已保存&lt;当前 - 用户更新您的程序
2向基地添加新数据
3在首选项上保存当前版本
b)如果表格结构已更改(添加或删除字段)
1增加数据库的版本号(请参阅扩展OrmLiteSqliteOpenHelper类)
2当用户第一次进入你的程序时,将调用方法'onUpgrade'(在你的扩展OrmLiteSqliteOpenHelper类中),它将被转移到旧的和新的版本号。
答案 3 :(得分:2)
我不想在每次升级时删除数据库,或者在添加每个字段后写一个更新代码,所以...
我试图这样做:
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
ArrayList<String> tableNames = getTableNames(database);
for (Class clazz : daoClasses) {
try {
Annotation annotation = clazz.getAnnotation(DatabaseTable.class);
if (annotation != null && annotation instanceof DatabaseTable) {
String tableName = ((DatabaseTable) annotation).tableName();
if (tableName.isEmpty()) {
tableName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);
}
if(!tableNames.contains(tableName)){
TableUtils.createTable(connectionSource, clazz);
} else {
addColumns(database, tableName, clazz);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private ArrayList<String> getTableNames(SQLiteDatabase database){
ArrayList<String> tableNames = new ArrayList<>();
Cursor cursor = database.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
if (cursor.moveToFirst()) {
while ( !cursor.isAfterLast() ) {
tableNames.add(cursor.getString(0));
cursor.moveToNext();
}
}
cursor.close();
return tableNames;
}
private void addColumns(SQLiteDatabase database, String tableName, Class clazz){
Cursor mCursor = database.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null);
for (Field field : clazz.getDeclaredFields()) {
try {
DatabaseField annotationField = field.getAnnotation(DatabaseField.class);
if (annotationField != null && !annotationField.foreign()){
String columnName = field.getName();
boolean hasColumn = mCursor.getColumnIndex(columnName) != -1;
if (!hasColumn) {
String columnType = field.getType().getSimpleName();
if(columnType.equals(String.class.getSimpleName())){
columnType = "TEXT";
} else {
columnType = columnType.toUpperCase();
}
database.execSQL(MessageFormat.format("ALTER TABLE `{0}` ADD COLUMN {1} {2};", tableName, columnName, columnType));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
mCursor.close();
}
我希望这段代码可以更好。
在这里,我不会删除从dao删除的旧表和列,而且我不会创建外国字段(我不确定是否需要它)。