SQLiteOpenHelper onUpgrade()混淆Android

我正在做我的第一个应用程序与数据库,我有一点点了解onUpgrade函数的麻烦。 我的数据库有一个表和一个项目和一个最喜欢的列,以便用户可以collections一个项目。 我看到的大多数实现只是删除表并重build它,但我不想这样做。 我想能够添加更多的项目到表中。

当应用程序通过android marketplace升级时,数据库是否知道它的版本号? 所以,我可以增加代码中的版本号,然后将其导出到市场,当用户第一次启动升级版本时,onUpgrade将被调用?

如果是这样的话,我的onUpgrade会简单地从文件中拉出来,并添加数据库项目。这是一个标准的做事方式,或者有更好的方式来处理这在Android中。 我正在尽可能保持标准。

谢谢

好吧,在遇到更大的问题之前,您应该知道SQLite在ALTER TABLE命令上是有限的,它允许addrename只有在重新创build表时才能执行删除/删除操作。

您应始终具有新的表创build查询,并将其用于升级并传输任何现有数据。 注意:onUpgrade方法为你的sqlite帮助器对象运行一个,你需要处理其中的所有表。

那么升级build议是什么:

  • 的BeginTransaction
  • 运行一个表创build, if not exists (我们正在做一个升级,所以表可能不存在,它会失败改变和下降)
  • 在列表中放入现有的列List<String> columns = DBUtils.GetColumns(db, TableName);
  • 备份表( ALTER table " + TableName + " RENAME TO 'temp_" + TableName
  • 创build新表(最新的表创build模式)
  • 获取与新列的交集,这次从升级后的表中取出columns.retainAll(DBUtils.GetColumns(db, TableName));
  • 恢复数据( String cols = StringUtils.join(columns, ","); db.execSQL(String.format( "INSERT INTO %s (%s) SELECT %s from temp_%s", TableName, cols, cols, TableName));
  • 删除备份表( DROP table 'temp_" + TableName
  • setTransactionSuccessful

(这不处理表降级,如果您重命名列,您没有得到传输的现有数据列名不匹配)。

 public static List<String> GetColumns(SQLiteDatabase db, String tableName) { List<String> ar = null; Cursor c = null; try { c = db.rawQuery("select * from " + tableName + " limit 1", null); if (c != null) { ar = new ArrayList<String>(Arrays.asList(c.getColumnNames())); } } catch (Exception e) { Log.v(tableName, e.getMessage(), e); e.printStackTrace(); } finally { if (c != null) c.close(); } return ar; } public static String join(List<String> list, String delim) { StringBuilder buf = new StringBuilder(); int num = list.size(); for (int i = 0; i < num; i++) { if (i != 0) buf.append(delim); buf.append((String) list.get(i)); } return buf.toString(); } 

在Pentium10的优秀答案旁边,下面是一些很好的例子:

  • Android AOSP: com.android.providers.calendar.CalendarDatabaseHelper.java

  • Android AOSP: com.android.browser.BrowserProvider.java

  • OpenIntents记事本: org.openintents.notepad.NotePadProvider.java

感谢您澄清onUpgrade()将不支持删除/删除语句@Pentium 10

对于那些想要知道onUpgrade()被调用的确切时刻的人,在调用getReadableDatabase()或getWriteableDatabase()的时候。

对于那些不清楚它是如何确保它被触发的…答案是: 当提供给SqLiteOpenHelper的构造函数的数据库版本被更新时,它被触发 。 这是一个例子

 public class dbSchemaHelper extends SQLiteOpenHelper { private String sql; private final String D_TAG = "FundExpense"; //update this to get onUpgrade() method of sqliteopenhelper class called static final int DB_VERSION = 2; static final String DB_NAME = "fundExpenseManager"; public dbSchemaHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); // TODO Auto-generated constructor stub } 

现在到… onUpgrade()

 @Override public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER"; arg0.execSQL(sql); } 

我一直在使用由@ Pentium10提出的解决scheme很长一段时间,但今天我遇到了一个问题,在做了alter table之后,getColumns从原始表中仍然返回相同的列(在新版本的db表中受灾市长结构一些列添加了一些其他的),真的不知道为什么select语句不能反映结构的变化,更多的是在再次创build我的表之前,select语句仍然返回列! 当表格不被重新创build!

所以我pipe理解决这个问题更新getColumns方法使用pragma table_info ,如下所示:

  /** * Get a list of column base_dictionary for the selected table * * @param db * Database that contains the table * @param tableName * Table name to be used * @return A List of column name */ public static List<String> getColumns(SQLiteDatabase db, String tableName) { List<String> ar = null; Cursor c = null; try { c = db.rawQuery("pragma table_info(" + tableName + ")", null); ar = new ArrayList<String>(); if (c != null && c.moveToFirst()) { do { ar.add(c.getString(c.getColumnIndexOrThrow("name"))); } while (c.moveToNext()); c.close(); } } catch (Exception e) { Log.v(tableName, e.getMessage(), e); e.printStackTrace(); } finally { if (c != null) c.close(); } return ar; }