Quand SQLiteOpenHelper onCreate () / onUpgrade () est-il exécuté?

293

J'ai créé mes tables dans mon SQLiteOpenHelper onCreate()mais je reçois

SQLiteException: no such table

ou

SQLiteException: no such column

les erreurs. Pourquoi?

REMARQUE:

(Ceci est le résumé fusionné de dizaines de questions similaires chaque semaine. Tenter de fournir ici une question / réponse wiki "canonique" de la communauté afin que toutes ces questions puissent être dirigées vers une bonne référence.)

laalto
la source
12
@Ndupza Ce n'est pas un problème réel, j'en ai juste marre d'écrire la même réponse / commentaire pour la Nème fois.
laalto

Réponses:

352

SQLiteOpenHelper onCreate()et les onUpgrade()rappels sont invoqués lorsque la base de données est réellement ouverte, par exemple par un appel à getWritableDatabase(). La base de données n'est pas ouverte lorsque l'objet d'assistance de base de données lui-même est créé.

SQLiteOpenHelperversions les fichiers de base de données. Le numéro de version est l' intargument transmis au constructeur . Dans le fichier de base de données, le numéro de version est stocké dans PRAGMA user_version.

onCreate()n'est exécuté que lorsque le fichier de base de données n'existe pas et vient d'être créé. Si onCreate()renvoie avec succès (ne lève pas d'exception), la base de données est supposée être créée avec le numéro de version demandé. En conséquence, vous ne devez pas attraper de SQLExceptions en onCreate()vous-même.

onUpgrade()n'est appelé que lorsque le fichier de base de données existe mais que le numéro de version stocké est inférieur à celui demandé dans le constructeur. leonUpgrade() doit mettre à jour le schéma de table vers la version demandée.

Lors de la modification du schéma de table dans code ( onCreate()), vous devez vous assurer que la base de données est mise à jour. Deux approches principales:

  1. Supprimez l'ancien fichier de base de données afin qu'il onCreate()soit à nouveau exécuté. Ceci est souvent préféré au moment du développement où vous avez le contrôle sur les versions installées et la perte de données n'est pas un problème. Quelques façons de supprimer le fichier de base de données:

    • Désinstallez l'application. Utilisez le gestionnaire d'application ou à adb uninstall your.package.namepartir du shell.

    • Effacer les données d'application. Utilisez le gestionnaire d'applications.

  2. Incrémentez la version de la base de données afin qu'elle onUpgrade()soit invoquée. C'est un peu plus compliqué car plus de code est nécessaire.

    • Pour les mises à niveau de schéma de temps de développement où la perte de données n'est pas un problème, vous pouvez simplement utiliser execSQL("DROP TABLE IF EXISTS <tablename>")in pour supprimer vos tables existantes et appeler onCreate()pour recréer la base de données.

    • Pour les versions publiées, vous devez implémenter la migration des données onUpgrade()afin que vos utilisateurs ne perdent pas leurs données.

laalto
la source
2
@Laalto // migration des données dans onUpgrade () // Pouvez-vous expliquer à ce sujet.
bCliks
2
@bala Pas dans le cadre de cette question / réponse. Si vous avez une question, n'hésitez pas à la poster sous forme de question.
laalto
2
@Jaskey Le numéro de version correspond à votre code, c'est-à-dire à quelle version de schéma le code s'attend à fonctionner. Si le fichier est plus ancien (à partir d'une version précédente de votre application), il doit être mis à niveau.
laalto
4
Donc, je dois coder en dur la VERSION DB dans SQLiteHelper chaque fois que je modifie le schéma, de sorte que lorsque l'ancienne application s'exécute et obtient la connexion db et la trouve ancienne, puis onUpgrade sera trgiigered au lieu de onCreate, est-ce ceci droite?
Jaskey
2
Je vous remercie ! Cela a du sens pour moi. Veuillez vérifier si je comprends bien. Nous devons donc faire 1. chaque fois que nous mettons à jour le schéma, modifiez la variable DB_VERSION (code dur). 2. Dans onUpdate(), vérifiez chaque ancienne version et effectuez la migration des données appropriée. Et puis, lorsqu'un utilisateur met à jour son application (il a d'anciens fichiers db), onUpgradeil est déclenché et, si l'utilisateur est nouvellement installé, il onCreate()est déclenché.
Jaskey
97

Pour ajouter des points manquants ici, conformément à la demande de Jaskey

La version de la SQLitebase de données est stockée dans le fichier de base de données.

catch est le constructeur

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

Ainsi, lorsque le constructeur d'aide de base de données est appelé avec un name (2e paramètre), la plate-forme vérifie si la base de données existe ou non et si la base de données existe, elle obtient les informations de version à partir de l'en-tête du fichier de base de données et déclenche le bon rappel.

Comme déjà expliqué dans la réponse précédente, si la base de données avec le nom n'existe pas, elle se déclenche onCreate.

L'explication ci-dessous explique onUpgrade cas avec un exemple.

Disons que votre première version de l'application avait le DatabaseHelper(extension SQLiteOpenHelper) avec le constructeur passant la version en tant 1que puis vous avez fourni une application mise à niveau avec le nouveau code source ayant la version passée en tant que 2, puis automatiquement lorsque le DatabaseHelperest construit, la plate-forme se déclenche onUpgradeen voyant le fichier existe déjà, mais la version est inférieure à la version actuelle que vous avez passée.

Supposons maintenant que vous envisagez de fournir une troisième version de l'application avec la version db as 3(la version db est augmentée uniquement lorsque le schéma de la base de données doit être modifié). Dans de telles mises à niveau incrémentielles, vous devez écrire la logique de mise à niveau de chaque version de manière incrémentielle pour un meilleur code maintenable

Exemple de pseudo-code ci-dessous:

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

Notez la breakdéclaration manquante au cas où 1et 2. C'est ce que je veux dire par mise à niveau incrémentielle.

Dites si l'ancienne version est 2et nouvelle version 4, la logique sera mise à jour de la base de données 2à 3puis à4

Si ancienne version est 3et nouvelle version 4, il suffit d' exécuter la logique de mise à niveau pour 3la4

Aun
la source
1
Je pense que vous voulez que votre switch (newVersion) soit switch (oldVersion) à la place. Vous pouvez également vérifier que newVersion est 4 (et non 5 ou 3; car votre logique suppose que la nouvelle version devrait être 4) .Comme c'est le cas, si l'ancienne version est 2 et la nouvelle version est 5, vous frappez le cas 4: et passez de 3 à 4 (ce qui ne devrait probablement pas être un comportement attendu).
joe p
à droite - faute de frappe .. mais si la nouvelle version est 5 -> alors il lèvera toujours IllegalStateException et le développeur le corrigera en ajoutant le cas 5 ..
Aun
1
Et si l'utilisateur met à jour son application de la version 2 à la version 3 uniquement? Dans ce cas également, tous les cas jusqu'au cas 4 s'exécuteront.
Paramvir Singh
6
L'utilisateur @param ne peut pas faire cela. Il peut mettre à niveau 2 vers la dernière (ici 4) uniquement.
Habeeb Perwad
20

onCreate()

  1. Lorsque nous créons DataBase pour la première fois (c'est-à-dire que la base de données n'existe pas), onCreate()créez une base de données avec la version qui est passée dans SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()La méthode consiste à créer les tables que vous avez définies et à exécuter tout autre code que vous avez écrit. Cependant, cette méthode ne sera appelée que si le fichier SQLite est manquant dans le répertoire de données de votre application ( /data/data/your.apps.classpath/databases).

  3. Cette méthode ne sera pas appelée si vous avez modifié votre code et relancé dans l'émulateur. Si vous souhaitez onCreate()exécuter, vous devez utiliser adb pour supprimer le fichier de base de données SQLite.

onUpgrade()

  1. SQLiteOpenHelper devrait appeler le super constructeur.
  2. La onUpgrade()méthode ne sera appelée que lorsque l'entier de version est plus grand que la version actuelle exécutée dans l'application.
  3. Si vous souhaitez que la onUpgrade()méthode soit appelée, vous devez incrémenter le numéro de version dans votre code.
jeet parmar
la source
1
Pourriez-vous élaborer davantage votre réponse en ajoutant un peu plus de description sur la solution que vous proposez?
abarisone
10

Peut-être que je suis trop tard, mais je voudrais partager ma réponse courte et douce. Veuillez cocher Réponse pour un même problème. Il va certainement vous aider. Plus de spécifications détaillées.

Si vous êtes sûr de la syntaxe de création de table, cela peut arriver lorsque vous ajoutez une nouvelle colonne dans votre même table, pour cela ...

1) Désinstallez de votre appareil et exécutez-le à nouveau.

OU

2) Réglage -> application -> ClearData

OU

3) Changement DATABASE_VERSIONdans votre classe "DatabaseHandler" (Si vous avez ajouté une nouvelle colonne, elle se mettra à jour automatiquement)

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

OU

4) Changement DATABASE_NAMEdans votre classe "DatabaseHandler" (j'ai rencontré le même problème. Mais je réussis en changeant DATABASE_NAME.)

shital
la source
J'ai ma propre base de données et j'utilise la classe SQLiteAssetHelper. Donc, j'ai créé le script DB by sql avant et la base de données a été créée. En utilisant SQLiteAssetHelper, il ne pouvait pas copier la base de données avant de désinstaller l'application de l'émulateur ou du périphérique, car il s'agissait d'une base de données avec la même version.
Behzad
4

Points à retenir lors de l'extension SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - Cela devrait être appelé la première ligne du constructeur
  2. remplacer onCreateetonUpgrade (si nécessaire)
  3. onCreatene sera invoqué que lorsque getWritableDatabase()ou getReadableDatabase()est exécuté. Et cela ne sera invoqué qu'une seule fois lorsqu'un DBNamespécifié dans la première étape n'est pas disponible. Vous pouvez ajouter une requête de création de table suronCreate méthode
  4. Chaque fois que vous voulez ajouter une nouvelle table, changez simplement DBversionet faites les requêtes dans la onUpgradetable ou désinstallez simplement puis installez l'application.
JibinNajeeb
la source
3

onCreate est appelé pour la première fois lorsque la création de tables est nécessaire. Nous devons remplacer cette méthode où nous écrivons le script de création de table qui est exécuté par SQLiteDatabase. méthode execSQL. Après avoir exécuté lors du premier déploiement, cette méthode ne sera plus appelée.

onUpgrade Cette méthode est appelée lorsque la version de la base de données est mise à niveau. Supposons que pour le premier déploiement, la version de la base de données était 1 et dans le deuxième déploiement, il y a eu un changement dans la structure de la base de données, comme l'ajout d'une colonne supplémentaire dans le tableau. Supposons que la version de la base de données soit 2 maintenant.

Faxriddin Abdullayev
la source
2

Vous pouvez créer une base de données et une table comme

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

Remarque: si vous souhaitez créer une autre table ou ajouter des colonnes ou aucune table, incrémentez simplement la VERSION

Enamul Haque
la source
2

La base de données SQLite remplace deux méthodes

1) onCreate (): Cette méthode n'est invoquée qu'une seule fois lorsque l'application est démarrée pour la première fois. Donc, il n'a appelé qu'une seule fois

2) onUpgrade () Cette méthode appelée lorsque nous changeons la version de la base de données, puis cette méthode est invoquée. Elle est utilisée pour modifier la structure de la table comme l'ajout d'une nouvelle colonne après la création du schéma de base de données.

sushant suryawanshi
la source
1

aucune telle table trouvée ne se trouve principalement lorsque vous n'avez pas ouvert la SQLiteOpenHelperclasse avec getwritabledata()et avant cela, vous devez également appeler le constructeur make avec le nom de la base de données et la version. Et OnUpgradeest appelé chaque fois qu'il y a une valeur de mise à niveau dans le numéro de version donné en SQLiteOpenHelperclasse.

Ci-dessous, l'extrait de code (aucune colonne trouvée ne peut être due à un sort dans le nom de la colonne):

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
la source
1

Si vous oubliez de fournir une chaîne "nom" comme deuxième argument au constructeur, il crée une base de données "en mémoire" qui est effacée lorsque vous fermez l'application.

phreakhead
la source
0

Désinstallez votre application de l'émulateur ou du périphérique. Exécutez à nouveau l'application. (OnCreate () n'est pas exécuté lorsque la base de données existe déjà)

Nand gopal
la source
0

Le nom de votre base de données doit se terminer par .db et vos chaînes de requête doivent avoir un terminateur (;)

Omer Haqqani
la source
0

Revérifiez votre requête dans votre classe DatabaseHandler / DatabaseManager (que vous ayez jamais prise)

venu
la source
0

Dans mon cas, je reçois des éléments du fichier XML avec <string-array>, où je stocke <item>s. Dans ces <item>s, je tiens des chaînes SQL et les applique un par un avec databaseBuilder.addMigrations(migration). J'ai fait une erreur, j'ai oublié d'ajouter \avant le devis et j'ai eu l'exception:

android.database.sqlite.SQLiteException: aucune colonne de ce type: une_valeur (code 1 SQLITE_ERROR):, lors de la compilation: INSERT INTO nom_table (id, nom) VALEURS (1, une_valeur)

Voici donc une bonne variante:

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

La méthode de Sqliteopenhelper possède des méthodes de création et de mise à niveau, create est utilisé lors de la première création d'une table et la méthode de mise à niveau est appelée à chaque fois que le nombre de colonnes de la table est modifié.

Vishwa Pratap
la source
La méthode onUpgrade est appelée lorsque la version de la base de données augmente, pas lorsque le nombre de colonnes est modifié. Réf: developer.android.com/reference/android/database/sqlite/… , int, int)
Roger Huang