Когда запускается SQLiteOpenHelper onCreate () / onUpgrade ()?

293

Я создал свои таблицы в моем, SQLiteOpenHelper onCreate()но получаю

SQLiteException: no such table

или

SQLiteException: no such column

ошибки. Зачем?

НОТА:

(Это объединенное резюме десятков подобных вопросов каждую неделю. Попытка предоставить «канонический» вопрос / ответ вики сообщества для того, чтобы все эти вопросы могли быть направлены на хорошую ссылку.)

laalto
источник
12
@Ndupza Это не моя проблема, просто надоело писать один и тот же ответ / комментарий в N-й раз.
laalto

Ответы:

352

SQLiteOpenHelper onCreate()и onUpgrade()обратные вызовы вызываются, когда база данных фактически открыта, например, путем вызова getWritableDatabase(). База данных не открывается при создании самого вспомогательного объекта базы данных.

SQLiteOpenHelperверсии файлов базы данных. Номер версии - это intаргумент, передаваемый конструктору . В файле базы данных номер версии хранится в PRAGMA user_version.

onCreate()запускается только тогда, когда файл базы данных не существует и только что был создан. Если onCreate()возвращается успешно (не выдает исключение), предполагается, что база данных будет создана с запрошенным номером версии. Как следствие, вы не должны ловить SQLExceptions в onCreate()себе.

onUpgrade()вызывается только тогда, когда файл базы данных существует, но номер сохраненной версии меньше, чем запрашивается в конструкторе. onUpgrade()Следует обновить схему таблицы для запрашиваемой версии.

При изменении схемы таблицы в code ( onCreate()) вы должны убедиться, что база данных обновлена. Два основных подхода:

  1. Удалите старый файл базы данных, чтобы onCreate()запустить его снова. Это часто предпочитается во время разработки, когда у вас есть контроль над установленными версиями, и потеря данных не является проблемой. Несколько способов удалить файл базы данных:

    • Удалите приложение. Используйте менеджер приложений или adb uninstall your.package.nameиз оболочки.

    • Очистить данные приложения. Используйте менеджер приложений.

  2. Увеличьте версию базы данных, чтобы onUpgrade()она вызывалась. Это немного сложнее, так как требуется больше кода.

    • Для обновления схемы времени разработки, когда потеря данных не является проблемой, вы можете просто использовать ее execSQL("DROP TABLE IF EXISTS <tablename>")для удаления существующих таблиц и вызова onCreate()для воссоздания базы данных.

    • Для выпущенных версий вы должны реализовать миграцию данных, onUpgrade()чтобы ваши пользователи не потеряли свои данные.

laalto
источник
2
@Laalto // перенос данных в onUpgrade () // Можете ли вы объяснить это.
bCliks,
2
@bala Не в рамках этого вопроса / ответа. Если у вас есть вопрос, не стесняйтесь отправить его как вопрос.
Лаальто
2
@Jaskey Номер версии для вашего кода, то есть с какой версией схемы будет работать код. Если файл более старый (из предыдущей версии вашего приложения), его необходимо обновить.
Лаальто
4
Итак, мне нужно жестко кодировать DB VERSION в SQLiteHelper каждый раз, когда я изменяю схему, чтобы, когда старое приложение запускается и получает соединение с БД и обнаруживает, что оно старое, а затем onUpgrade будет обрабатываться вместо onCreate, это право?
Jaskey
2
Спасибо ! Это имеет смысл для меня. Пожалуйста, проверьте, правильно ли я понимаю. Так что нам нужно сделать 1. каждый раз, когда мы обновляем схему, изменяем переменную DB_VERSION (жесткий код). 2. onUpdate()Проверьте каждую старую версию и выполните правильную миграцию данных. И затем, когда пользователь обновляет свое приложение (у него есть старые файлы базы данных), onUpgradeбудет запущен, а если пользователь только что установил, onCreate()запускается.
Jaskey
97

Чтобы добавить недостающие очки здесь, согласно запросу Jaskey

Версия базы данных хранится в SQLiteфайле базы данных.

улов это конструктор

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

Поэтому, когда вспомогательный конструктор базы данных вызывается с name (2-й параметр), платформа проверяет, существует ли база данных или нет, и если база данных существует, она получает информацию о версии из заголовка файла базы данных и запускает правильный обратный вызов

Как уже объяснялось в предыдущем ответе, если база данных с таким именем не существует, она срабатывает onCreate.

Ниже объяснение объясняет onUpgradeслучай с примером.

Скажем, ваша первая версия приложения имела DatabaseHelper(расширяющуюся SQLiteOpenHelper) версию с передачей в конструктор as, 1а затем вы предоставили обновленное приложение с новым исходным кодом, в котором версия была передана как 2, а затем автоматически при DatabaseHelperсоздании платформа запускается onUpgrade, увидев, что файл уже существует, но версия ниже текущей версии, которую вы прошли.

Теперь предположим, что вы планируете предоставить третью версию приложения с версией db как 3(версия db увеличивается только тогда, когда требуется изменить схему базы данных). В таких инкрементальных обновлениях вы должны писать логику обновления для каждой версии постепенно для лучшего сопровождения кода.

Пример псевдокода ниже:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  switch(oldVersion) {
    case 1:
       //upgrade logic from version 1 to 2
    case 2:
       //upgrade logic from version 2 to 3
    case 3:
       //upgrade logic from version 3 to 4
       break;
    default:
       throw new IllegalStateException(
                "onUpgrade() with unknown oldVersion " + oldVersion);
  }
}

Обратите внимание на недостающее breakутверждение в случае 1и 2. Это то, что я имею в виду под постепенным обновлением.

Скажем, если старая версия 2и новая версия 4, то логика будет обновлять базу данных с 2до, 3а затем до4

Если старая версия 3и новая версия 4, она будет просто запустить обновления логики 3в4

Aun
источник
1
Я думаю, что вы хотите, чтобы ваш переключатель (newVersion) был переключателем (oldVersion) вместо этого. Вы также можете проверить, что newVersion равен 4 (а не 5 или 3; поскольку ваша логика предполагает, что новая версия должна быть 4). Как и в случае старой версии 2, а новой версии 5, вы ударить по делу 4: и обновить с 3 до 4 (что, вероятно, не следует ожидать поведения).
Джо П
правильно - опечатка .. но если новая версия 5 ->, то она всегда будет выдавать исключение IllegalStateException, и разработчик исправит это, добавив случай 5 ..
Aun
1
Что если пользователь обновит свое приложение только с версии 2 до 3? В этом случае также будут выполняться все случаи до случая 4.
Парамвир Сингх
6
Пользователь @param не может этого сделать. Он может обновить только 2 до последней версии (здесь 4).
Хабиб Perwad
20

onCreate()

  1. Когда мы создаем базу данных в первый раз (т.е. база данных не существует), onCreate()создайте базу данных с версией, которая передается в SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()Метод создает таблицы, которые вы определили, и выполняет любой другой код, который вы написали. Однако этот метод вызывается только в том случае, если в каталоге данных вашего приложения отсутствует файл SQLite ( /data/data/your.apps.classpath/databases).

  3. Этот метод не будет вызываться, если вы изменили свой код и перезапустились в эмуляторе. Если вы хотите onCreate()запустить, вам нужно использовать adb для удаления файла базы данных SQLite.

onUpgrade()

  1. SQLiteOpenHelper должен вызвать супер конструктор.
  2. onUpgrade()Метод будет вызываться только тогда , когда версия целое больше , чем текущая версия работает в приложении.
  3. Если вы хотите, чтобы onUpgrade()метод вызывался, вам нужно увеличить номер версии в своем коде.
jeet parmar
источник
1
Не могли бы вы более подробно изложить свой ответ, добавив немного больше описания предлагаемого вами решения?
abarisone
10

Может быть, я опоздал, но я хотел бы поделиться своим коротким и сладким ответом. Пожалуйста, проверьте ответ на ту же проблему. Это определенно поможет вам. Нет более глубоких спецификаций.

Если вы уверены в синтаксисе создания таблицы, то это может произойти при добавлении нового столбца в ту же таблицу, для этого ...

1) Удалите с вашего устройства и запустите его снова.

ИЛИ

2) Настройка -> приложение -> ClearData

ИЛИ

3) Измените DATABASE_VERSIONсвой класс DatabaseHandler (если вы добавили новый столбец, он обновится автоматически)

public DatabaseHandler(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

ИЛИ

4) Изменение DATABASE_NAMEв вашем классе «DatabaseHandler» (я столкнулся с той же проблемой. Но я преуспел, изменив DATABASE_NAME.)

shital
источник
У меня есть своя собственная БД и использующий класс SQLiteAssetHelper. Итак, я создал сценарий БД с помощью sql, и БД была создана. Используя SQLiteAssetHelper, он не мог скопировать БД, пока не удалил приложение из эмулятора или устройства, потому что это была БД с той же версией.
Бехзад
4

Что следует помнить при расширении SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - Это должно быть вызвано первой строкой конструктора
  2. переопределить onCreateи onUpgrade(при необходимости)
  3. onCreateбудет вызываться только когда getWritableDatabase()или getReadableDatabase()выполняется. И это будет вызвано только один раз, когда DBNameуказанный на первом шаге недоступен. Вы можете добавить создать запрос таблицы по onCreateметоду
  4. Всякий раз, когда вы хотите добавить новую таблицу, просто измените DBversionи выполните запросы в onUpgradeтаблице или просто удалите, а затем установите приложение.
JibinNajeeb
источник
3

onCreate вызывается впервые, когда необходимо создание таблиц. Нам нужно переопределить этот метод, где мы пишем скрипт для создания таблицы, который выполняется SQLiteDatabase. метод execSQL. После выполнения при первом развертывании этот метод не будет вызываться далее.

onUpgrade Этот метод вызывается при обновлении версии базы данных. Предположим, что для первого развертывания версия базы данных была равна 1, а во втором развертывании произошли изменения в структуре базы данных, такие как добавление дополнительного столбца в таблицу. Предположим, версия базы данных сейчас 2.

Факсриддин Абдуллаев
источник
2

Вы можете создать базу данных и таблицу, как

public class DbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "testdatbase.db";
private static final int VERSION = 1;

public DbHelper(Context context) {
    super(context, DBNAME, null, VERSION);
    // TODO Auto-generated constructor stub
}

@Override
public void onCreate(SQLiteDatabase db) {
    // TODO Auto-generated method stub
    db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text");

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS BookDb");
    onCreate(db);
  }
}

Примечание: если вы хотите создать другую таблицу или добавить столбцы или нет такой таблицы, просто увеличьте VERSION

Энамул Хак
источник
2

База данных Sqlite переопределяет два метода

1) onCreate (): этот метод вызывается только один раз, когда приложение запускается в первый раз. Так называется только один раз

2) onUpgrade () Этот метод вызывается, когда мы меняем версию базы данных, затем вызывается этот метод. Он используется для изменения структуры таблицы, например, для добавления нового столбца после создания схемы БД.

Sushant Suryawanshi
источник
1

такая таблица не найдена, в основном, когда вы не открыли SQLiteOpenHelperкласс с, getwritabledata()и перед этим вам также нужно вызвать конструктор make с базой данных и версией. И OnUpgradeвызывается всякий раз, когда есть значение обновления в номере версии, указанном в SQLiteOpenHelperклассе.

Ниже приведен фрагмент кода (такой столбец не может быть найден из-за заклинания в имени столбца):

public class database_db {
    entry_data endb;
    String file_name="Record.db";
    SQLiteDatabase sq;
    public database_db(Context c)
    {
        endb=new entry_data(c, file_name, null, 8);
    }
    public database_db open()
    {
        sq=endb.getWritableDatabase();
        return this;
    }
    public Cursor getdata(String table)
    {
        return sq.query(table, null, null, null, null, null, null);
    }
    public long insert_data(String table,ContentValues value)
    {
        return sq.insert(table, null, value);
    }
    public void close()
    {
        sq.close();
    }
    public void delete(String table)
    {
        sq.delete(table,null,null);
    }
}
class entry_data extends SQLiteOpenHelper
{

    public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory,
                      int version) {
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase sqdb) {
        // TODO Auto-generated method stub

        sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);");

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
          onCreate(db);
    }

}
Bharat Lalwani
источник
1

Если вы забыли предоставить строку «имя» в качестве второго аргумента для конструктора, она создаст базу данных «в памяти», которая будет удалена при закрытии приложения.

phreakhead
источник
0

Удалите ваше приложение с эмулятора или устройства. Запустите приложение еще раз. (OnCreate () не выполняется, когда база данных уже существует)

Нанд гопал
источник
0

Имя вашей базы данных должно заканчиваться на .db, а строки запроса должны иметь терминатор (;)

Омер Хаккани
источник
0

Еще раз проверьте ваш запрос в классе DatabaseHandler / DatabaseManager (который вы когда-либо использовали)

Venu
источник
0

В моем случае я получаю элементы из XML-файла <string-array>, где храню <item>s. В этих <item>я держу строки SQL и применяю их по одному databaseBuilder.addMigrations(migration). Я сделал одну ошибку, забыл добавить\ перед цитатой и получил исключение:

android.database.sqlite.SQLiteException: такого столбца нет: some_value (код 1 SQLITE_ERROR): при компиляции: INSERT INTO имя_таблицы (id, name) VALUES (1, some_value)

Итак, это правильный вариант:

<item>
    INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>
CoolMind
источник
-2

В методе Sqliteopenhelper есть методы create и upgrade, create используется, когда любая таблица создается впервые, и метод upgrade будет вызываться каждый раз, когда изменяется номер столбца таблицы.

Вишва Пратап
источник
Метод onUpgrade вызывается при увеличении версии базы данных, а не при изменении номера столбца. Ссылка: developer.android.com/reference/android/database/sqlite/… , int, int)
Роджер Хуанг,