Kapan SQLiteOpenHelper onCreate () / onUpgrade () dijalankan?

293

Saya telah membuat tabel saya di SQLiteOpenHelper onCreate()tetapi saya terima

SQLiteException: no such table

atau

SQLiteException: no such column

kesalahan. Mengapa?

CATATAN:

(Ini adalah ringkasan gabungan dari puluhan pertanyaan serupa setiap minggu. Berusaha untuk memberikan pertanyaan / jawaban wiki komunitas "kanonik" di sini sehingga semua pertanyaan itu dapat diarahkan ke referensi yang baik.)

laalto
sumber
12
@ Nupupza Ini bukan masalah saya yang sebenarnya, hanya muak menulis jawaban / komentar yang sama untuk yang kesekian kalinya.
laalto

Jawaban:

352

SQLiteOpenHelper onCreate()dan onUpgrade()panggilan balik dipanggil saat database sebenarnya dibuka, misalnya dengan panggilan ke getWritableDatabase(). Database tidak dibuka ketika objek pembantu database itu sendiri dibuat.

SQLiteOpenHelperversi file database. Nomor versi adalah intargumen yang diteruskan ke konstruktor . Dalam file database, nomor versi disimpan di PRAGMA user_version.

onCreate()hanya berjalan ketika file database tidak ada dan baru saja dibuat. Jika onCreate()kembali dengan sukses (tidak melempar pengecualian), database diasumsikan dibuat dengan nomor versi yang diminta. Sebagai implikasinya, Anda tidak harus menangkap SQLExceptions di onCreate()diri Anda.

onUpgrade()hanya dipanggil ketika file database ada tetapi nomor versi yang disimpan lebih rendah dari yang diminta dalam konstruktor. The onUpgrade()harus memperbarui tabel skema ke versi yang diminta.

Saat mengubah skema tabel dalam kode ( onCreate()), Anda harus memastikan database diperbarui. Dua pendekatan utama:

  1. Hapus file database lama agar onCreate()dijalankan kembali. Ini sering lebih disukai pada waktu pengembangan di mana Anda memiliki kontrol atas versi yang diinstal dan kehilangan data tidak menjadi masalah. Beberapa cara untuk menghapus file database:

    • Copot pemasangan aplikasi. Gunakan manajer aplikasi atau adb uninstall your.package.namedari shell.

    • Hapus data aplikasi. Gunakan manajer aplikasi.

  2. Tambahkan versi database sehingga onUpgrade()dipanggil. Ini sedikit lebih rumit karena lebih banyak kode diperlukan.

    • Untuk peningkatan skema waktu pengembangan di mana kehilangan data tidak menjadi masalah, Anda bisa menggunakannya execSQL("DROP TABLE IF EXISTS <tablename>")untuk menghapus tabel yang ada dan menelepon onCreate()untuk membuat ulang basis data.

    • Untuk versi yang dirilis, Anda harus menerapkan migrasi data onUpgrade()agar pengguna Anda tidak kehilangan data mereka.

laalto
sumber
2
@ Laalto // migrasi data di onUpgrade () // Bisakah Anda jelaskan tentang ini.
bCliks
2
@ Balala Tidak dalam lingkup pertanyaan / jawaban ini. Jika Anda memiliki pertanyaan, jangan ragu untuk mempostingnya sebagai pertanyaan.
laalto
2
@Jaskey Nomor versi untuk kode Anda, yaitu versi skema apa yang ingin ditentang oleh kode. Jika file lebih lama (dari versi aplikasi Anda sebelumnya), ia perlu ditingkatkan.
laalto
4
Jadi, saya perlu mengkode DB VERSION di SQLiteHelper setiap kali saya memodifikasi skema, sehingga ketika aplikasi lama berjalan dan mendapatkan koneksi db dan menemukan itu sudah tua, dan kemudian Upgrade akan di-trgiigered alih-alih onCreate, apakah ini Baik?
Jaskey
2
Terima kasih ! Ini masuk akal bagi saya. Harap verifikasi jika saya mengerti dengan baik. Jadi 1. yang perlu kami lakukan 1. setiap kali kami memperbarui skema, ubah variabel DB_VERSION (hard code). 2. Di onUpdate(), periksa setiap versi lama dan lakukan migrasi data yang tepat. Dan kemudian ketika pengguna memperbarui aplikasi mereka (mereka memiliki file db lama), onUpgradeakan Dipicu, dan jika pengguna baru menginstal, onCreate()dipicu.
Jaskey
97

Untuk lebih lanjut menambahkan poin yang hilang di sini, sesuai permintaan Jaskey

Versi database disimpan dalam SQLitefile database.

menangkap adalah konstruktor

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

Jadi ketika konstruktor pembantu database dipanggil dengan name(param 2), platform memeriksa apakah database ada atau tidak dan jika database ada, ia mendapatkan informasi versi dari header file database dan memicu panggilan balik yang tepat

Seperti yang sudah dijelaskan dalam jawaban yang lebih lama, jika database dengan nama tidak ada, itu dipicu onCreate.

Penjelasan di bawah ini menjelaskan onUpgradekasus dengan contoh.

Katakanlah, versi aplikasi pertama Anda memiliki versi DatabaseHelper(extending SQLiteOpenHelper) dengan konstruktor yang lewat sebagai 1dan kemudian Anda memberikan aplikasi yang ditingkatkan dengan kode sumber baru setelah versi berlalu 2, kemudian secara otomatis ketika DatabaseHelperdibangun, platform memicu onUpgradedengan melihat file yang sudah ada, tetapi versi ini lebih rendah dari versi saat ini yang telah Anda lewati.

Sekarang katakan Anda berencana untuk memberikan versi ketiga aplikasi dengan versi db sebagai 3(versi db hanya meningkat ketika skema database akan dimodifikasi). Dalam peningkatan bertahap seperti itu, Anda harus menulis logika pemutakhiran dari setiap versi secara bertahap untuk mendapatkan kode yang dapat dikelola dengan lebih baik

Contoh kode semu di bawah ini:

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

Perhatikan breakpernyataan yang hilang dalam kasus 1dan 2. Inilah yang saya maksud dengan peningkatan bertahap.

Katakan jika versi yang lama 2dan versi yang baru 4, maka logikanya akan memutakhirkan basis data dari 2ke 3dan kemudian ke4

Jika versi lama adalah 3dan versi baru ini 4, itu hanya akan menjalankan logika upgrade untuk 3ke4

Aun
sumber
1
Saya pikir Anda ingin beralih Anda (newVersion) menjadi beralih (oldVersion) sebagai gantinya. Anda mungkin juga ingin memverifikasi bahwa versi baru adalah 4 (dan bukan 5, atau 3; karena logika Anda mengasumsikan versi baru harus 4). Seperti itu, jika versi lama 2 dan versi baru 5, Anda akan tekan case 4: dan upgrade dari 3 ke 4 (yang mungkin seharusnya tidak diharapkan perilaku).
joe p
benar - salah ketik .. tetapi jika versi baru 5 -> maka itu akan selalu membuang IllegalStateException dan pengembang akan memperbaikinya dengan menambahkan case 5 ..
Aun
1
Bagaimana jika pengguna hanya memutakhirkan aplikasinya dari versi 2 ke 3? Dalam hal itu juga, semua kasus hingga kasus 4 akan berjalan.
Paramvir Singh
6
Pengguna @param tidak bisa melakukan itu. Ia hanya dapat memutakhirkan 2 ke yang terbaru (di sini 4).
Habeeb Perwad
20

onCreate()

  1. Ketika kita membuat DataBase pada pertama kalinya (mis. Basis Data tidak ada) onCreate()buat basis data dengan versi yang diteruskan SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()Metode membuat tabel yang telah Anda tetapkan dan menjalankan kode lain yang Anda tulis. Namun, metode ini hanya akan dipanggil jika file SQLite hilang di direktori data aplikasi Anda ( /data/data/your.apps.classpath/databases).

  3. Metode ini tidak akan dipanggil jika Anda telah mengubah kode Anda dan diluncurkan kembali di emulator. Jika Anda ingin onCreate()menjalankan Anda harus menggunakan adb untuk menghapus file database SQLite.

onUpgrade()

  1. SQLiteOpenHelper harus memanggil konstruktor super.
  2. The onUpgrade()Metode hanya akan dipanggil saat versi bilangan bulat lebih besar dari versi saat berjalan di app.
  3. Jika Anda ingin onUpgrade()metode dipanggil, Anda perlu menambahkan nomor versi dalam kode Anda.
jeet parmar
sumber
1
Bisakah Anda menjelaskan lebih lanjut jawaban Anda dengan menambahkan sedikit deskripsi tentang solusi yang Anda berikan?
abarisone
10

Mungkin saya terlambat tetapi saya ingin membagikan jawaban singkat dan manis saya. Silakan periksa Jawab untuk masalah yang sama. Itu pasti akan membantu Anda. Tidak ada spesifikasi yang lebih dalam.

Jika Anda yakin tentang sintaks untuk membuat tabel, daripada yang mungkin terjadi ketika Anda menambahkan kolom baru di tabel yang sama, untuk itu ...

1) Hapus instalasi dari perangkat Anda dan jalankan lagi.

ATAU

2) Pengaturan -> aplikasi -> ClearData

ATAU

3) Ubah DATABASE_VERSIONkelas "DatabaseHandler" Anda (Jika Anda telah menambahkan kolom baru maka akan ditingkatkan secara otomatis)

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

ATAU

4) Ubah DATABASE_NAMEkelas "DatabaseHandler" Anda (saya menghadapi masalah yang sama. Tetapi saya berhasil dengan mengubah DATABASE_NAME.)

shital
sumber
Saya memiliki DB sendiri dan menggunakan kelas SQLiteAssetHelper. Jadi, saya membuat DB oleh skrip sql sebelumnya dan db telah dibuat. Dengan menggunakan SQLiteAssetHelper, ia tidak dapat menyalin DB hingga menghapus instalan aplikasi dari emulator atau perangkat, karena itu adalah db dengan versi yang sama.
Behzad
4

Poin yang perlu diingat saat memperpanjang SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - Ini harus dipanggil baris pertama konstruktor
  2. timpa onCreatedan onUpgrade(jika perlu)
  3. onCreateakan dipanggil hanya ketika getWritableDatabase()atau getReadableDatabase()dieksekusi. Dan ini hanya akan dipanggil sekali ketika DBNameditentukan pada langkah pertama tidak tersedia. Anda bisa menambahkan membuat kueri tabel pada onCreatemetode
  4. Setiap kali Anda ingin menambahkan tabel baru, ubah DBversiondan lakukan pertanyaan dalam onUpgradetabel atau cukup uninstall lalu instal aplikasi.
JibinNajeeb
sumber
3

onCreate dipanggil untuk pertama kalinya ketika pembuatan tabel diperlukan. Kita perlu mengganti metode ini di mana kita menulis skrip untuk pembuatan tabel yang dieksekusi oleh SQLiteDatabase. metode execSQL Setelah mengeksekusi dalam penyebaran pertama kali, metode ini tidak akan dipanggil seterusnya.

onUpgrade Metode ini dipanggil ketika versi database ditingkatkan. Misalkan untuk penyebaran pertama kali, versi database adalah 1 dan di penyebaran kedua ada perubahan dalam struktur database seperti menambahkan kolom tambahan dalam tabel. Misalkan versi database adalah 2 sekarang.

Faxriddin Abdullayev
sumber
2

Anda dapat membuat basis data & tabel seperti

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

Catatan: jika Anda ingin membuat tabel lain atau menambahkan kolom atau tidak ada tabel seperti itu, cukup tambahkan VERSI

Enamul Haque
sumber
2

Database Sqlite mengesampingkan dua metode

1) onCreate (): Metode ini dipanggil hanya sekali ketika aplikasi dimulai pada kali pertama. Jadi itu disebut hanya sekali

2) onUpgrade () Metode ini dipanggil ketika kita mengubah versi database, maka metode ini dipanggil. Ini digunakan untuk mengubah struktur tabel seperti menambahkan kolom baru setelah membuat DB Schema

suryawanshi sushant
sumber
1

tidak ada tabel yang ditemukan terutama ketika Anda belum membuka SQLiteOpenHelperkelas dengan getwritabledata()dan sebelum ini Anda juga harus memanggil make constructor dengan databasename & versi. Dan OnUpgradedipanggil setiap kali ada nilai upgrade dalam nomor versi yang diberikan di SQLiteOpenHelperkelas.

Berikut ini cuplikan kode (Tidak ditemukan kolom seperti itu karena ejaan dalam nama kolom):

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
sumber
1

Jika Anda lupa untuk memberikan string "nama" sebagai argumen kedua ke konstruktor, itu menciptakan database "dalam memori" yang terhapus ketika Anda menutup aplikasi.

phreakhead
sumber
0

Copot aplikasi Anda dari emulator atau perangkat. Jalankan aplikasi lagi. (OnCreate () tidak dieksekusi ketika database sudah ada)

Nand gopal
sumber
0

Nama database Anda harus diakhiri dengan .db juga string kueri Anda harus memiliki terminator (;)

Omer Haqqani
sumber
0

Periksa kembali pertanyaan Anda di kelas DatabaseHandler / DatabaseManager Anda (yang pernah Anda ambil)

venu
sumber
0

Dalam kasus saya, saya mendapatkan item dari file XML dengan <string-array>, tempat saya menyimpan <item>. Dalam <item>s ini saya memegang string SQL dan menerapkan satu-per-satu dengan databaseBuilder.addMigrations(migration). Saya membuat satu kesalahan, lupa menambahkan \sebelum penawaran dan mendapatkan pengecualian:

android.database.sqlite.SQLiteException: tidak ada kolom seperti itu: some_value (kode 1 SQLITE_ERROR):, saat mengompilasi: INSERT INTO table_name (id, name) VALUES (1, some_value)

Jadi, ini adalah varian yang tepat:

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

Metode Sqliteopenhelper memiliki metode membuat dan memutakhirkan, membuat digunakan ketika setiap tabel pertama kali dibuat dan metode pemutakhiran akan dipanggil setiap kali setiap kali jumlah kolom tabel diubah.

Vishwa Pratap
sumber
Metode onUpgrade dipanggil ketika versi database meningkat, bukan ketika jumlah kolom diubah. Ref: developer.android.com/reference/android/database/sqlite/… , int, int)
Roger Huang