SQLiteOpenHelper onUpgrade () Путаница Android - PullRequest
48 голосов
/ 17 августа 2010

Я делаю свое первое приложение с базой данных, и у меня возникли небольшие проблемы с пониманием функции onUpgrade. В моей базе данных есть таблица с элементами и столбцом избранного, чтобы пользователь мог добавить элемент в избранное. Большинство реализаций, которые я вижу, просто отбрасывают таблицу и воссоздают ее, но я не хочу этого делать. Я хочу иметь возможность добавлять больше элементов в таблицу.

Когда приложение обновляется через Android Marketplace, знает ли база данных свой номер версии? Так можно ли увеличить номер версии в коде, а затем экспортировать его на рынок, и когда пользователь впервые загрузит обновленную версию, будет вызван onUpgrade?

Если это так, мой onUpgrade просто извлечет из файла и добавит элементы базы данных. Это стандартный способ работы или есть лучший способ справиться с этим в Android. Я стараюсь оставаться как можно более стандартным.

Спасибо

Ответы [ 4 ]

108 голосов
/ 17 августа 2010

Хорошо, перед тем, как столкнуться с более крупными проблемами, вы должны знать, что SQLite ограничен командой ALTER TABLE, она позволяет add и rename только удаление / удаление, что выполняется при воссоздании таблицы.

Вы всегда должны иметь под рукой новый запрос на создание таблицы и использовать его для обновления и передачи любых существующих данных. Обратите внимание: что методы onUpgrade запускают один для вашего вспомогательного объекта sqlite, и вам нужно обработать все таблицы в нем.

Итак, что рекомендуется при обновлении:

  • BeginTransaction
  • запустить создание таблицы с помощью if not exists (мы проводим обновление, поэтому таблица может еще не существовать, она не сможет изменить и удалить)
  • внести в список существующие столбцы List<String> columns = DBUtils.GetColumns(db, TableName);
  • резервная таблица (ALTER table " + TableName + " RENAME TO 'temp_" + TableName)
  • создать новую таблицу (новейшая схема создания таблицы)
  • получить пересечение с новыми столбцами, на этот раз столбцы взяты из обновленной таблицы (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();
}
39 голосов
/ 12 июня 2011

Рядом с отличным ответом Pentium10 приведены несколько хороших примеров из живого кода:

6 голосов
/ 23 декабря 2011

Спасибо за разъяснение, что onUpgrade () не будет поддерживать операторы Remove / Drop @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);
}
1 голос
/ 11 апреля 2014

Я давно использую решение, предложенное @ Pentium10, но сегодня у меня возникла проблема, после выполнения изменения таблицы getColumns из исходной таблицы по-прежнему возвращает те же столбцы (в новой версии db таблицы пострадали изменения структуры мэра, некоторые столбцы добавили некоторые другие), на самом деле я не знаю, почему оператор SELECT не отражает структурные изменения, более того, перед созданием моей таблицы оператор SELECT по-прежнему возвращает столбцы! Когда таблица еще не воссоздана!

Так что мне удается решить эту проблему, обновляя метод 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...