Коли запускається SQLiteOpenHelper onCreate () / onUpgrade ()?


293

Я створив свої таблиці у своєму, SQLiteOpenHelper onCreate()але отримую

SQLiteException: no such table

або

SQLiteException: no such column

помилки. Чому?

ПРИМІТКА:

(Це об'єднаний підсумок десятків подібних питань щотижня. Спроба надати тут "канонічне" питання щодо вікі-спільноти, щоб усі ці запитання могли бути спрямовані на хороший довідник.)


12
@Ndupza Це не є моєю актуальною проблемою, просто надоїли писати ту ж відповідь / коментар вчетверте.
laalto

Відповіді:


352

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

SQLiteOpenHelperверсії файлів бази даних. Номер версії - це intаргумент, переданий конструктору . У файлі бази даних номер версії зберігається PRAGMA user_version.

onCreate()запускається лише тоді, коли файл бази даних не існував і був лише створений. Якщо onCreate()успішно повертається (не викидає виключення), база даних вважається створеною із запитуваним номером версії. Як імплікації, ви не повинні зловити SQLExceptionз в onCreate()себе.

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

Змінюючи схему таблиці в коді ( onCreate()), ви повинні переконатися, що база даних оновлюється. Два основні підходи:

  1. Видаліть старий файл бази даних, щоб onCreate()він запустився знову. Це часто бажано в час розробки, коли ви маєте контроль над встановленими версіями і втрата даних не є проблемою. Деякі способи видалення файла бази даних:

    • Видаліть програму. Використовуйте менеджер програм або adb uninstall your.package.nameз оболонки.

    • Очистити дані програми. Використовуйте менеджер програм.

  2. Збільшити версію бази даних, щоб onUpgrade()її викликали. Це трохи складніше, оскільки потрібно більше коду.

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

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


2
@Laalto // міграція даних у onUpgrade () // Чи можете ви поясніть це?
bCliks

2
@bala Не входить до цього питання / відповіді. Якщо у вас є питання, не соромтесь розмістити його як запитання.
laalto

2
@Jaskey Номер версії для вашого коду, тобто версії схеми, з якою очікується працювати код. Якщо файл старіший (з попередньої версії вашого додатка), його потрібно оновити.
laalto

4
Отже, мені потрібно жорстко кодувати DB VERSION у SQLiteHelper кожного разу, коли я змінюю схему, щоб коли старий додаток запускався і отримував db-з'єднання і знаходив його старим, а потім onUpgrade буде тригігерірован замість onCreate, це правильно?
Жаскі

2
Дякую ! Це має для мене сенс. Будь ласка, перевірте, чи я добре розумію. Отже, нам потрібно зробити щоразу, коли ми оновлюємо схему, змінюйте змінну DB_VERSION (жорсткий код). 2. onUpdate()Перевірте стару версію та проведіть належну міграцію даних. І тоді, коли користувач оновить свою програму (у них старі файли db), onUpgradeбуде запущено, а якщо користувач знову встановиться, onCreate()буде запущено.
Jaskey

97

Щоб додатково додати сюди відсутні точки, відповідно до запиту Жаскі

Версія бази даних зберігається у SQLiteфайлі бази даних.

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

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

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

Як уже було пояснено у попередній відповіді, якщо база даних з іменем не існує, вона спрацьовує onCreate.

Нижче пояснюється пояснення onUpgradeвипадку з прикладом.

Скажімо, у вашій першій версії програми була DatabaseHelper(розширена SQLiteOpenHelper) версія, що передається конструктором, 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


1
Я думаю, ви хочете, щоб ваш перемикач (newVersion) був комутатором (oldVersion) замість цього. Ви також можете перевірити, що newVersion дорівнює 4 (а не 5 або 3; оскільки ваша логіка припускає, що новій версії має бути 4). Так, якщо стара версія 2, а нова версія 5, ви натисніть на випадок 4: та оновіть з 3 до 4 (що, мабуть, не слід очікувати поведінки).
joe p

право - помилка .. але якщо нова версія 5 -> то він завжди буде кидати IllegalStateException і розробник буде фіксуючи його, додавши корпус 5 ..
Аун

1
Що робити, якщо користувач оновить свій додаток лише з версії 2 до 3? У цьому випадку також будуть запущені всі випадки до випадку 4.
Paramvir Singh

6
Користувач @param цього не може зробити. Він може оновити лише 2 до останніх (тут 4).
Habeeb Perwad

20

onCreate()

  1. Коли ми створюємо DataBase вперше (тобто База даних не існує), 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()метод викликався, вам потрібно збільшити номер версії у своєму коді.

1
Чи можете ви детальніше розглянути свою відповідь, додавши трохи більше опису про рішення, яке ви надаєте?
абарізон

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.)


У мене є власна БД та використовується клас SQLiteAssetHelper. Отже, я створив БД за допомогою sql-скрипту раніше, і було створено db. Використовуючи SQLiteAssetHelper, він не міг скопіювати БД до видалення програми з емулятора чи пристрою, оскільки це був db з тією ж версією.
Бехзад

4

Окуляри, які слід пам’ятати при розширенні SQLiteOpenHelper

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

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);
  }
}

Примітка: якщо ви хочете створити іншу таблицю або додати стовпці чи немає такої таблиці, просто збільште ВЕРСІЮ


2

База даних Sqlite замінює два методи

1) onCreate (): Цей метод використовується лише один раз при першому запуску програми. Так дзвонили лише один раз

2) onUpgrade () Цей метод викликається, коли ми змінюємо версію бази даних, тоді цей метод викликається. Він використовується для зміни структури таблиці, як додавання нового стовпця після створення схеми БД


1

жодної такої таблиці не знайдено, головним чином, коли ви не відкривали SQLiteOpenHelperклас, getwritabledata()і перед цим вам також потрібно зателефонувати зробити конструктор з ім'ям бази даних та версією. І 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);
    }

}

1

Якщо ви забудете надати рядок "ім'я" як другий аргумент конструктору, він створює базу даних "в пам'яті", яка стирається, коли ви закриваєте додаток.


0

Видаліть програму з емулятора чи пристрою. Запустіть додаток ще раз. (OnCreate () не виконується, коли база даних вже існує)


0

Ім'я вашої бази даних повинно закінчуватися .db, також у ваших рядках запиту повинен бути термінатор (;)


0

Перевірте свій запит у класі DatabaseHandler / DatabaseManager (який ви коли-небудь брали)


0

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

android.database.sqlite.SQLiteException: немає такого стовпця: some_value (код 1 SQLITE_ERROR):, під час компіляції: ВСТАВИТЬ INTO table_name (id, name) VALUES (1, some_value)

Отже, це правильний варіант:

<item>
    INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>

-2

Метод Sqliteopenhelper має методи створення та оновлення, створюється використовується, коли будь-яка таблиця створена вперше, а метод оновлення буде викликатися кожен раз, коли змінюється номер стовпця таблиці.


Метод onUpgrade називається, коли збільшується версія бази даних, а не коли змінюється кількість стовпця. Ref: developer.android.com/reference/android/database/sqlite/… , int, int)
Роджер Хуанг,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.