SQLiteOpenHelper onCreate () / onUpgrad () कब चलता है?


293

मैंने अपनी तालिकाएँ अपने में बना ली हैं SQLiteOpenHelper onCreate()लेकिन प्राप्त करते हैं

SQLiteException: no such table

या

SQLiteException: no such column

त्रुटियों। क्यों?

ध्यान दें:

(यह हर हफ्ते इसी तरह के सवालों का दसवां सारांश है। यहां एक "विहित" सामुदायिक विकि प्रश्न / उत्तर देने का प्रयास किया जा रहा है ताकि उन सभी प्रश्नों को एक अच्छे संदर्भ में निर्देशित किया जा सके।)


12
@ नदुपजा यह मेरी एक वास्तविक समस्या नहीं है, बस एनथ समय के लिए एक ही उत्तर / टिप्पणी लिखना तंग आ गया है।
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
@ लल्टो // ऑनग्रुप में डेटा माइग्रेशन () // क्या आप इस बारे में बता सकते हैं।
14:14 बजे

2
@ इस प्रश्न / उत्तर के दायरे में नहीं। यदि आपके पास कोई प्रश्न है, तो इसे प्रश्न के रूप में पोस्ट करने के लिए स्वतंत्र महसूस करें।
laalto

2
@Jaskey संस्करण संख्या आपके कोड के लिए होती है यानी कोड किस स्कीमा संस्करण के विरुद्ध चलने की अपेक्षा करता है। यदि फ़ाइल पुरानी है (आपके ऐप के पिछले संस्करण से), तो इसे अपग्रेड करने की आवश्यकता है।
लालाटो

4
इसलिए, मुझे हर बार स्कीमा को संशोधित करते समय SQLiteHelper में DB संस्करण को हार्ड कोड करने की आवश्यकता होती है, ताकि जब पुराना ऐप चले और db कनेक्शन प्राप्त करें और यह पुराना हो, और तब onUpgrad को onCreate के बजाय ट्रिगर किया जाएगा, क्या यह है सही?
जसकी

2
धन्यवाद ! यह मेरे लिए समझ में आता है। कृपया सत्यापित करें कि क्या मैं अच्छी तरह से समझता हूं। हमें ऐसा करने की आवश्यकता है। 1. हर बार जब हम स्कीमा को अपडेट करते हैं, तो DB_VERSION चर (हार्ड ड्राइव) को संशोधित करें। 2. onUpdate(), हर पुराने संस्करण की जाँच करें और उचित डेटा माइग्रेशन करें। और फिर जब कोई उपयोगकर्ता अपने ऐप को अपडेट करेगा (उनके पास पुरानी डीबी फाइलें हैं), onUpgradeतो ट्रिगर हो जाएगा, और यदि उपयोगकर्ता नया स्थापित है, onCreate()तो ट्रिगर किया गया है।
जसकी

97

जस्की के अनुरोध के अनुसार, लापता बिंदुओं को और जोड़ने के लिए

SQLiteडेटाबेस फ़ाइल डेटाबेस फ़ाइल में संग्रहीत है ।

कैच कंस्ट्रक्टर है

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

इसलिए जब डेटाबेस हेल्पर कंस्ट्रक्टर को name(द्वितीय परम) के साथ बुलाया जाता है , तो प्लेटफ़ॉर्म यह चेक करता है कि डेटाबेस मौजूद है या नहीं और यदि डेटाबेस मौजूद है, तो उसे डेटाबेस फ़ाइल हेडर से संस्करण की जानकारी मिल जाती है और सही कॉल बैक ट्रिगर हो जाता है

जैसा कि पहले से ही पुराने उत्तर में समझाया गया है, अगर नाम वाला डेटाबेस मौजूद नहीं है, तो यह ट्रिगर हो जाता है 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 में अपग्रेड करें (जो शायद अपेक्षित व्यवहार नहीं होना चाहिए)।
जो पी। पी।

सही - टाइपो .. लेकिन अगर नया संस्करण 5 -> है, तो यह हमेशा IllegalStateException को फेंक देगा और डेवलपर इसे 5 केस जोड़कर ठीक कर देगा ..
Aun

1
क्या होगा यदि उपयोगकर्ता अपने ऐप को केवल संस्करण 2 से 3 में अपग्रेड करे? उस स्थिति में भी, केस 4 तक के सभी मामले चलेंगे।
परमवीर सिंह

6
@ अपरम उपयोगकर्ता ऐसा नहीं कर सकता। वह 2 से नवीनतम (यहाँ 4) को अपग्रेड कर सकता है।
हबीब परवाद

20

onCreate()

  1. जब हम पहली बार में DataBase बनाते हैं (यानी डेटाबेस मौजूद नहीं है) onCreate()उस संस्करण के साथ डेटाबेस बनाएँ, जो इसमें पारित हो गया है SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()विधि आपके द्वारा परिभाषित किसी भी अन्य कोड को परिभाषित करने और निष्पादित करने वाली तालिकाओं का निर्माण कर रही है। हालाँकि, यह विधि केवल तभी कॉल की जाएगी जब आपके ऐप के डेटा डायरेक्टरी ( /data/data/your.apps.classpath/databases) में SQLite फ़ाइल गायब हो ।

  3. यदि आपने अपना कोड बदल दिया है और एमुलेटर में रिलॉन्च किया हुआ है तो यह विधि नहीं कहलाएगी। यदि आप onCreate()चलाना चाहते हैं तो आपको SQLite डेटाबेस फ़ाइल को हटाने के लिए adb का उपयोग करने की आवश्यकता है।

onUpgrade()

  1. SQLiteOpenHelper सुपर कंस्ट्रक्टर को कॉल करना चाहिए।
  2. onUpgrade()जब संस्करण पूर्णांक अनुप्रयोग में चल रहे वर्तमान संस्करण से बड़ा है विधि केवल बुलाया जाएगा।
  3. यदि आप चाहते हैं कि onUpgrade()विधि को बुलाया जाए, तो आपको अपने कोड में संस्करण संख्या को बढ़ाना होगा।

1
क्या आप प्रदान किए गए समाधान के बारे में थोड़ा और विवरण जोड़कर अपने जवाब को विस्तृत कर सकते हैं?
अबारीसोन

10

हो सकता है कि मुझे बहुत देर हो गई हो लेकिन मैं अपने छोटे और मधुर उत्तर को साझा करना चाहूंगा। कृपया उत्तर की जाँच करें एक ही समस्या के लिए । यह निश्चित रूप से आपका मददगार होगा। कोई और अधिक विशिष्ट विनिर्देशों।

यदि आप तालिका बनाने के लिए वाक्यविन्यास के बारे में आश्वस्त हैं, तो यह तब हो सकता है जब आप अपनी उसी तालिका में नया कॉलम जोड़ते हैं, उसके लिए ...

1) अपने डिवाइस से स्थापना रद्द करें और इसे फिर से चलाएं।

या

2) सेटिंग -> ऐप -> क्लियरडाटा

या

3)DATABASE_VERSION अपने "डेटाबेसहैंडलर" वर्ग में बदलाव करें (यदि आपने नया कॉलम जोड़ा है तो यह स्वतः ही अपग्रेड हो जाएगा)

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

या

4)DATABASE_NAME अपने "डेटाबेसहैंडलर" वर्ग में बदलाव करें (मुझे उसी समस्या का सामना करना पड़ा। लेकिन मैं बदलकर सफल हुआ DATABASE_NAME।)


मेरा अपना DB है और SQLiteAssetHelper वर्ग का उपयोग कर रहा है। इसलिए, मैंने पहले sql स्क्रिप्ट द्वारा DB बनाया और db बनाया गया। SQLiteAssetHelper का उपयोग करके यह एप्लिकेशन को एमुलेटर या डिवाइस को अनइंस्टॉल करने तक DB को कॉपी नहीं कर सकता है, क्योंकि यह उसी संस्करण के साथ db था।
बेहज़ाद

4

जब याद करने के लिए अंक SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - यह निर्माणकर्ता की पहली पंक्ति को लागू करना चाहिए
  2. ओवरराइड onCreateऔर onUpgrade(यदि आवश्यक हो)
  3. onCreateकेवल तब ही लागू किया जाएगा जब getWritableDatabase()या getReadableDatabase()निष्पादित किया जाएगा। और यह केवल एक बार लागू होगा जब DBNameपहले चरण में निर्दिष्ट उपलब्ध नहीं है। आप onCreateविधि पर तालिका क्वेरी जोड़ सकते हैं
  4. जब भी आप नई तालिका जोड़ना चाहते हैं तो बस परिवर्तन करें DBversionऔर onUpgradeतालिका में प्रश्नों को करें या बस स्थापना रद्द करें और फिर एप्लिकेशन इंस्टॉल करें।

3

ऑनक्रिएट को पहली बार तब बुलाया जाता है जब टेबल के निर्माण की आवश्यकता होती है। हमें इस पद्धति को ओवरराइड करने की आवश्यकता है जहां हम टेबल निर्माण के लिए स्क्रिप्ट लिखते हैं जिसे SQLiteDatabase द्वारा निष्पादित किया जाता है। execSQL विधि। पहली बार तैनाती में निष्पादित करने के बाद, इस विधि को आगे नहीं कहा जाएगा।

onUpgrad डेटाबेस संस्करण अपग्रेड होने पर इस विधि को कहा जाता है। मान लें कि पहली बार परिनियोजन के लिए, डेटाबेस संस्करण 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

आपके डेटाबेस का नाम समाप्त होना चाहिए। साथ ही आपके क्वेरी स्ट्रिंग्स में एक टर्मिनेटर (;) होना चाहिए।


0

डेटाबेसहैंडलर / डेटाबेस मैनजर क्लास (जो आपने कभी लिया है) में अपनी क्वेरी को रीचेक करें


0

मेरे मामले में मुझे XML-फ़ाइल से आइटम मिलते हैं <string-array>, जहां मैं स्टोर करता हूं <item>। इन <item>एस में मैं एसक्यूएल स्ट्रिंग्स रखता हूं और एक-एक करके लागू करता हूं databaseBuilder.addMigrations(migration)। मैंने एक गलती की, \उद्धरण से पहले जोड़ना भूल गया और अपवाद मिला:

android.database.sqlite.SQLiteException: ऐसा कोई कॉलम नहीं: some_value (कोड 1 SQLITE_ERROR):, संकलन करते समय: INSERT INTO table_name (id, name) VALUES (1, some_value)

तो, यह एक सही प्रकार है:

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

-2

Sqliteopenhelper की विधि में बनाने और अपग्रेड करने की विधियाँ हैं, जब किसी तालिका को पहली बार बनाया जाता है तो अपग्रेड का उपयोग किया जाता है और जब भी तालिका के कॉलम की संख्या बदली जाती है तो अपग्रेड विधि को कॉल किया जाएगा।


onUpgrad विधि को उस समय कहा जाता है जब डेटाबेस संस्करण बढ़ता है, न कि जब कॉलम की संख्या बदली जाती है। Ref: developer.android.com/reference/android/database/sqlite/… , int, int)
रोजर हुआंग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.