问题
I'm actually developing an app which is using ORMLite library (which is wonderful btw) but I'm a beginner using it.
I have a question about the update of the database inside the device.
Let's say that someone download my app on the Google Play. Few months later I will certainly populate some tables with new entries.
When this person is doing an update of the app, how can I just update the database with my new entries and keep the old ones inside it.
To be more clear, imagine that the user answered questions in my app. When I will introduce new questions, how can I insert them in the db when he updates my app and keep the questions that have already been answered ?
回答1:
When this person is doing an update of the app, how can I just update the database with my new entries and keep the old ones inside it.
The idea is to use the version number that is passed to the onUpgrade(...)
method. With ORMLite, the OrmLiteSqliteOpenHelper.onUpgrade(...)
method takes an oldVersion
and newVersion
number. You then can write conversion code into your application that is able to convert the data from the old format and update the schema.
For more information, see the ORMLite docs on the subject:
http://ormlite.com/docs/upgrade-schema
To quote, you could do something like the following:
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;");
}
If you have existing data that you need to convert then you should do the conversions in SQL if possible.
Another alternative would be to have an Account
entity and an OldAccount
entity that point to the same table-name. Then you can read in OldAccount
entities using the oldAccountDao
, convert them to Account
entities, and then update them using the accountDao
back to the same table. You need to be careful about object caches here.
回答2:
I do it this way:
@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);
}
This will incrementally update the users db independent from which db version he is coming.
回答3:
Little information, is not clear whether the changes you have table structure.
a) If you do not change the database structure.
1 In the new version of your program when you start checking a previously saved version (eg in preferences) with the current (see PackageManager.getPackageInfo)
saved = 0 - User just installed the new version
saved < current - User updates your program
2 Add new data to base
3 Save current version on preferences
b) If the table structure has changed (added or remove fields)
1 Increase the version number of your database (see your extends OrmLiteSqliteOpenHelper class)
2 When the user first runs into your program, method 'onUpgrade' will be called (in your extends OrmLiteSqliteOpenHelper class) which will be transferred to old and new version numbers.
- Read the existing data in the cache (temp)
- recreate table
- Add the data from the cache + your new data
回答4:
I don't like to drop database at every upgrade, or write an update code after I add each field, so ...
I'm trying to do it like this:
@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();
}
I hope this code can be better.
Here, i don't delete old tables and columns that were removed from dao's, and I don't create foreign fields (I'm not sure if i need it).
来源:https://stackoverflow.com/questions/13782084/ormlite-update-of-the-database