Android: DB संस्करण को अपग्रेड करना और नई तालिका जोड़ना


117

मैंने अपने ऐप के लिए पहले से ही साइक्लाइट टेबल बना लिया है, लेकिन अब मैं डेटाबेस में एक नई टेबल जोड़ना चाहता हूं।

मैंने नीचे के रूप में DB संस्करण को बदल दिया

private static final int DATABASE_VERSION = 2;

और तालिका बनाने के लिए जोड़ा गया स्ट्रिंग

private static final String DATABASE_CREATE_color = 
   "CREATE TABLE IF NOT EXISTS files(color text, incident_id text)";

onCreateऔर onUpgradeनीचे:

@Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(DATABASE_CREATE_incident);
        database.execSQL(DATABASE_CREATE_audio);
        database.execSQL(DATABASE_CREATE_video);
        database.execSQL(DATABASE_CREATE_image);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //drop table and add new tables when version 2 released.
        db.execSQL(DATABASE_CREATE_color);

    }

लेकिन किसी कारण से नई तालिका नहीं बनाई जा रही है। मैं क्या गलत कर रहा हूं?


यह एक और दिलचस्प समाधान है, लेकिन अब तक मैंने देखा सबसे मजबूत संस्करण यहां है
सुरगाछ

जवाबों:


280

1. OnCreate () और onUpgrad () के बारे में

onCreate(..)जब भी ऐप को नए सिरे से इंस्टॉल किया जाता है तो उसे कॉल किया जाता है। onUpgradeजब भी ऐप को अपग्रेड और लॉन्च किया जाता है और डेटाबेस संस्करण समान नहीं होता है।

2. DB संस्करण बढ़ाना

आपको एक निर्माता की आवश्यकता है जैसे:

MyOpenHelper(Context context) {
   super(context, "dbname", null, 2); // 2 is the database version
}

महत्वपूर्ण: केवल ऐप वर्जन को बढ़ाना ही पर्याप्त नहीं है onUpgradeजिसे कहा जा सकता है!

3. अपने नए उपयोगकर्ताओं को मत भूलना!

जोड़ना मत भूलना

database.execSQL(DATABASE_CREATE_color);

आपके ऑनक्रिएट () विधि के साथ-साथ या नए इंस्टॉल किए गए ऐप्स में तालिका का अभाव होगा।

4. समय के साथ कई डेटाबेस परिवर्तनों से कैसे निपटें

जब आपके पास क्रमिक ऐप अपग्रेड होता है, जिसमें से कई में डेटाबेस अपग्रेड होता है, तो आप जांचना सुनिश्चित करते हैं oldVersion:

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   switch(oldVersion) {
   case 1:
       db.execSQL(DATABASE_CREATE_color);
       // we want both updates, so no break statement here...
   case 2:
       db.execSQL(DATABASE_CREATE_someothertable); 
   }
}

इस तरह जब कोई उपयोगकर्ता संस्करण 1 से संस्करण 3 में अपग्रेड करता है, तो उन्हें दोनों अपडेट मिलते हैं। जब कोई उपयोगकर्ता संस्करण 2 से 3 में अपग्रेड करता है, तो उन्हें केवल संशोधन 3 अपडेट प्राप्त होता है ... आखिरकार, जब भी आप अपडेट जारी करते हैं, तो अपग्रेड करने के लिए आप अपने उपयोगकर्ता आधार के 100% पर भरोसा नहीं कर सकते। कभी-कभी वे अपडेट को छोड़ देते हैं या 12 :)

5. विकास करते समय अपने संशोधन संख्या को नियंत्रण में रखें

और अंत में ... कॉलिंग

adb uninstall <yourpackagename>

पूरी तरह से एप्लिकेशन को अनइंस्टॉल करता है। जब आप फिर से स्थापित करते हैं, तो आपको हिट करने की गारंटी दी onCreateजाती है जो आपके द्वारा विकसित किए जा रहे स्ट्रैटोस्फियर में डेटाबेस संस्करण को बढ़ाने के लिए रखने के लिए आपको रखता है ...


5
# 4 के बारे में: क्या यह oldVersionतर्क पारित करने के लिए एक बेहतर विचार नहीं होगा ? यदि कोई अपग्रेड स्टेटमेंट रिपीटेबल हैं, तो आप उन्हें ज्यादातर अप-टू-डेट डेटाबेस पर दोहरा सकते हैं। यदि किसी एक कथन को सारणीबद्ध करना है, तो यह बहुत बुरा होगा।
ग्रीयसन

3
@ ग्रीसन: ग्रेट पॉइंट! ईमानदारी से, मैं वास्तव में इसके बारे में कभी नहीं सोचने के लिए थोड़ा बेवकूफ महसूस करता हूं। कभी-कभी मुझे लगता है कि हमें अपने मनचाहे तर्कों का उपयोग करने और बाकी की अनदेखी करने की आदत है!
9

1
आप डेटाबेस को नियंत्रित करते हैं, आप नाम क्यों बदलेंगे?
21

3
newVersionथोड़े बेकार है, जैसा कि आप हमेशा वर्तमान डेटाबेस संस्करण को वैसे भी कंस्ट्रक्टर में सेट करते हैं (भाग 2 देखें) और यह हमेशा मेल खाएगा। यहां मुख्य विचार यह है कि आप उपयोगकर्ता के newVersionबीच में हर दूसरे वृद्धिशील उन्नयन के माध्यम से गुजरने के बिना , जहां भी सीधे हैं, वहां से सिर्फ अपग्रेड नहीं करना चाहते हैं ।
jkschneider

2
@kai CREATE_READINGSतर्क कभी भी onUpgrade में नहीं होना चाहिए, क्योंकि यह onCreateआपके पहले संस्करण की विधि में था । onUpgradeस्विच में मामलों के बारे में सोचो "मैं FROM को अपग्रेड कर रहा हूं oldVersion"। यदि आप संस्करण 1 से अपग्रेड कर रहे थे, तो आप रीडिंग टेबल नहीं बनाएंगे, क्योंकि यह पहले से मौजूद होना चाहिए। उम्मीद है कि यह समझ में आता है ...
jkschneider

9

आपका कोड सही लगता है। मेरा सुझाव यह है कि डेटाबेस पहले से ही सोचता है कि यह उन्नत है। यदि आपने संस्करण संख्या को बढ़ाने के बाद परियोजना को निष्पादित किया है, लेकिन execSQLकॉल को जोड़ने से पहले , आपके परीक्षण उपकरण / एमुलेटर पर डेटाबेस पहले से ही यह मानता है कि यह संस्करण 2 पर है।

इसे सत्यापित करने का एक त्वरित तरीका संस्करण संख्या को 3 में बदलना होगा - यदि यह उसके बाद अपग्रेड करता है, तो आप जानते हैं कि यह सिर्फ इसलिए था क्योंकि आपका डिवाइस पहले से ही उन्नत था।


फिर, जैसा कि अपेक्षित था, आपका कोड ठीक था; बस तब नहीं जब इसे बढ़ाकर चलाया गया था। टेबल निर्माण को जोड़ने के लिए याद रखें onCreate()जैसे कि jkschneider ने बताया है।
ग्रीजॉन

2

आप SQLiteOpenHelper की onUpgradeविधि का उपयोग कर सकते हैं । OnUpgrad विधि में, आपको पुराने पैरामीटर को एक पैरामीटर के रूप में मिलता है।

में onUpgradeउपयोग एक switchऔर में से प्रत्येक caseडेटाबेस के वर्तमान संस्करण का ट्रैक रखने के संस्करण संख्या का उपयोग करें।

यह सबसे अच्छा है कि आप एक बार में 1 से बढ़ oldVersionकर newVersion, versionफिर से डेटाबेस चरण को अपग्रेड करें। यह बहुत उपयोगी होता है जब डेटाबेस संस्करण 1 के साथ कोई व्यक्ति डेटाबेस संस्करण 7 का उपयोग करने वाले संस्करण के लिए लंबे समय के बाद ऐप को अपग्रेड करता है, और कुछ असंगत परिवर्तनों के कारण ऐप क्रैश होने लगता है।

फिर डेटाबेस में अद्यतन सभी वार मामलों को कवर करते हुए, हर नए संस्करण के लिए किए गए डेटाबेस में बदलाव को शामिल करते हुए, और इस तरह आपके एप्लिकेशन को दुर्घटनाग्रस्त होने से बचाने के लिए चरण-वार किया जाएगा।

उदाहरण के लिए:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch (oldVersion) {
    case 1:
        String sql = "ALTER TABLE " + TABLE_SECRET + " ADD COLUMN " + "name_of_column_to_be_added" + " INTEGER";
        db.execSQL(sql);
        break;

    case 2:
        String sql = "SOME_QUERY";
        db.execSQL(sql);
        break;
    }

}

यदि आप उन ब्रेक स्टेटमेंट को हटा देते हैं तो आपको लूप की आवश्यकता नहीं होगी
ताश पेमहिवा

लेकिन पुराने मामले को अगले मामले @TashPemhiwa
Beulah Ana

एक स्विच स्टेटमेंट के कारण ब्रेक की आवश्यकता होती है, एक ही बार में कई केस चलाना संभव है - और अगर केस की शर्त पूरी नहीं होती है, तो भी ऐसा ही होगा, @BeulahAna
Tash Pemhiwa

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

2

@ jkschneider का जवाब सही है। हालांकि एक बेहतर तरीका है।

लिंक में वर्णित प्रत्येक अद्यतन के लिए एक sql फ़ाइल में आवश्यक परिवर्तन लिखें https://riggaroo.co.za/android-sqlite-database-use-onupgrad-correctly/

from_1_to_2.sql

ALTER TABLE books ADD COLUMN book_rating INTEGER;

from_2_to_3.sql

ALTER TABLE books RENAME TO book_information;

from_3_to_4.sql

ALTER TABLE book_information ADD COLUMN calculated_pages_times_rating INTEGER;
UPDATE book_information SET calculated_pages_times_rating = (book_pages * book_rating) ;

इन .sql फ़ाइलों को डेटाबेस के संस्करण के अनुसार onUpgrade () पद्धति में निष्पादित किया जाएगा।

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 4;

    private static final String DATABASE_NAME = "database.db";
    private static final String TAG = DatabaseHelper.class.getName();

    private static DatabaseHelper mInstance = null;
    private final Context context;

    private DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
    }

    public static synchronized DatabaseHelper getInstance(Context ctx) {
        if (mInstance == null) {
            mInstance = new DatabaseHelper(ctx.getApplicationContext());
        }
        return mInstance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(BookEntry.SQL_CREATE_BOOK_ENTRY_TABLE);
        // The rest of your create scripts go here.

    }


    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.e(TAG, "Updating table from " + oldVersion + " to " + newVersion);
        // You will not need to modify this unless you need to do some android specific things.
        // When upgrading the database, all you need to do is add a file to the assets folder and name it:
        // from_1_to_2.sql with the version that you are upgrading to as the last version.
        try {
            for (int i = oldVersion; i < newVersion; ++i) {
                String migrationName = String.format("from_%d_to_%d.sql", i, (i + 1));
                Log.d(TAG, "Looking for migration file: " + migrationName);
                readAndExecuteSQLScript(db, context, migrationName);
            }
        } catch (Exception exception) {
            Log.e(TAG, "Exception running upgrade script:", exception);
        }

    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    private void readAndExecuteSQLScript(SQLiteDatabase db, Context ctx, String fileName) {
        if (TextUtils.isEmpty(fileName)) {
            Log.d(TAG, "SQL script file name is empty");
            return;
        }

        Log.d(TAG, "Script found. Executing...");
        AssetManager assetManager = ctx.getAssets();
        BufferedReader reader = null;

        try {
            InputStream is = assetManager.open(fileName);
            InputStreamReader isr = new InputStreamReader(is);
            reader = new BufferedReader(isr);
            executeSQLScript(db, reader);
        } catch (IOException e) {
            Log.e(TAG, "IOException:", e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    Log.e(TAG, "IOException:", e);
                }
            }
        }

    }

    private void executeSQLScript(SQLiteDatabase db, BufferedReader reader) throws IOException {
        String line;
        StringBuilder statement = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            statement.append(line);
            statement.append("\n");
            if (line.endsWith(";")) {
                db.execSQL(statement.toString());
                statement = new StringBuilder();
            }
        }
    }
}

एक उदाहरण परियोजना उसी कड़ी में भी प्रदान की जाती है: https://github.com/riggaroo/AndroidDatabaseUpgrades


1
मैं बस यहाँ आने और उसी सलाह को लिखने वाला था। मुझे खुशी है कि आपने पहले ही यह कर लिया। लोगों को आपके द्वारा जुड़े लेख को जरूर पढ़ना चाहिए। यह वही है जो एंड्रॉइड SQLiteAssetHelper उन्नयन के लिए सिफारिश करता है। यह भी क्या सी.एल. ( SQLite विशेषज्ञ स्टैक ओवरफ़्लो पर यहाँ) की सिफारिश की
सुरगाछ

यह टिप्पणी मैं क्या देख रहा था। एसक्यूएल स्क्रिप्ट, +1
blueware

1

डेटाबेस संस्करण को संभालना अनुप्रयोग विकास का बहुत महत्वपूर्ण हिस्सा है। मुझे लगता है कि आपके पास पहले से ही क्लास AppDbHelper का विस्तार है SQLiteOpenHelper। जब आप इसे बढ़ाते हैं तो आपको इसे लागू करने onCreateऔर onUpgradeविधि की आवश्यकता होगी ।

  1. कब onCreateऔर onUpgradeतरीके बुलाए गए

    • onCreate जब नव स्थापित app कहा जाता है।
    • onUpgrade जब app अद्यतन कहा जाता है।
  2. डेटाबेस संस्करणों का आयोजन मैं एक वर्ग विधियों में संस्करणों का प्रबंधन करता हूं। इंटरफ़ेस माइग्रेशन का कार्यान्वयन बनाएँ। उदाहरण के लिए पहले संस्करण के लिए MigrationV1कक्षा बनाएं , दूसरा संस्करण बनाएं MigrationV1ToV2(ये मेरे नामकरण सम्मेलन हैं)


    public interface Migration {
        void run(SQLiteDatabase db);//create tables, alter tables
    }

उदाहरण प्रवास:

public class MigrationV1ToV2 implements Migration{
      public void run(SQLiteDatabase db){
        //create new tables
        //alter existing tables(add column, add/remove constraint)
        //etc.
     }
   }
  1. माइग्रेशन कक्षाओं का उपयोग करना

onCreate: जब onCreateसे बुलाया जाएगा जब आवेदन नए सिरे से स्थापित किया जाएगा, तो हमें सभी माइग्रेशन (डेटाबेस संस्करण अपडेट) को निष्पादित करने की भी आवश्यकता है। तो onCreateइस तरह दिखेगा:

public void onCreate(SQLiteDatabase db){
        Migration mV1=new MigrationV1();
       //put your first database schema in this class
        mV1.run(db);
        Migration mV1ToV2=new MigrationV1ToV2();
        mV1ToV2.run(db);
        //other migration if any
  }

onUpgrade: इस विधि को तब बुलाया जाएगा जब एप्लिकेशन पहले से इंस्टॉल हो और इसे नए एप्लिकेशन संस्करण में अपडेट किया जाए। यदि एप्लिकेशन में कोई डेटाबेस परिवर्तन होता है तो नए माइग्रेशन क्लास और इंक्रीमेंट डेटाबेस संस्करण में सभी डेटाबेस परिवर्तन करें।

उदाहरण के लिए, यह बताता है कि उपयोगकर्ता ने एप्लिकेशन इंस्टॉल किया है जिसमें डेटाबेस संस्करण 1 है, और अब डेटाबेस संस्करण 2 में अपडेट किया गया है (सभी स्कीमा अपडेट इन में रखा गया है MigrationV1ToV2)। अब जब एप्लिकेशन अपग्रेड किया जाता है, तो हमें डेटाबेस स्कीमा परिवर्तन को MigrationV1ToV2इस तरह लागू करके डेटाबेस को अपग्रेड करना होगा:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion < 2) {
        //means old version is 1
        Migration migration = new MigrationV1ToV2();
        migration.run(db);
    }
    if (oldVersion < 3) {
        //means old version is 2
    }
}

नोट: onUpgradeडेटाबेस स्कीमा में सभी अपग्रेड (उल्लेखित ) को निष्पादित किया जाना चाहिएonCreate

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.