অ্যান্ড্রয়েড: ডিবি সংস্করণ আপগ্রেড এবং নতুন সারণী যুক্ত করা


117

আমি ইতিমধ্যে আমার অ্যাপ্লিকেশনটির জন্য স্ক্লাইট টেবিল তৈরি করেছি, তবে এখন আমি ডাটাবেসে একটি নতুন টেবিল যুক্ত করতে চাই।

আমি নীচের মত ডিবি সংস্করণ পরিবর্তন করেছি

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(..)অ্যাপটি যখনই নতুনভাবে ইনস্টল করা হয় তখনই তাকে ডাকা হয়। onUpgradeঅ্যাপটি যখনই আপগ্রেড এবং লঞ্চ করা হয় তখনই ডাকা হয় এবং ডাটাবেস সংস্করণটি এক রকম হয় না।

২. ডিবি সংস্করণ বৃদ্ধি করা

আপনার যেমন একটি নির্মাতা প্রয়োজন:

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

গুরুত্বপূর্ণ: একমাত্র অ্যাপ্লিকেশন সংস্করণ বাড়ানো onUpgradeবলা যায় না!

3. আপনার নতুন ব্যবহারকারীদের ভুলবেন না!

যুক্ত করতে ভুলবেন না

database.execSQL(DATABASE_CREATE_color);

আপনার অনক্রিয়েট () পদ্ধতিতে পাশাপাশি বা নতুন ইনস্টল হওয়া অ্যাপ্লিকেশনগুলির টেবিলের অভাব হবে।

৪. সময়ের সাথে সাথে একাধিক ডাটাবেস পরিবর্তনের সাথে কীভাবে ডিল করতে হয়

যখন আপনার ক্রমাগত অ্যাপ্লিকেশন আপগ্রেড থাকে, যার মধ্যে বেশ কয়েকটিতে ডাটাবেস আপগ্রেড থাকে, আপনি অবশ্যই তা পরীক্ষা করে দেখতে চান 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 সংস্করণ 3 এ আপগ্রেড করে, তারা উভয় আপডেট পেয়ে যায়। যখন কোনও ব্যবহারকারী 2 থেকে 3 সংস্করণে আপগ্রেড করে, তারা কেবল পুনর্বিবেচনা 3 আপডেট পায় ... সর্বোপরি, আপনি প্রতিবার আপডেট প্রকাশের সময় আপগ্রেড করার জন্য আপনার ব্যবহারকারীর বেসের 100% গণনা করতে পারবেন না। কখনও কখনও তারা একটি আপডেট এড়িয়ে যান বা 12 :)

৫. বিকাশের সময় আপনার পুনর্বিবেচনা সংখ্যা নিয়ন্ত্রণে রাখা

এবং অবশেষে ... কলিং

adb uninstall <yourpackagename>

সম্পূর্ণ অ্যাপ্লিকেশন আনইনস্টল। আপনি যখন আবার ইনস্টল করেন, তখন আপনাকে আঘাত করার গ্যারান্টি দেওয়া হয় onCreateযা আপনাকে বিকাশের সাথে সাথে স্ট্র্যাটোস্ফিয়ারে ডাটাবেস সংস্করণ বাড়িয়ে রাখা থেকে বিরত রাখে ...


5
# 4 সম্পর্কিত: oldVersionপাস করা যুক্তিটি ব্যবহার করা কি আরও ভাল ধারণা হবে না ? যদি কোনও আপগ্রেড বিবৃতি পুনরাবৃত্তিযোগ্য হয় তবে আপনি সেগুলি বেশিরভাগ আপ টু ডেট ডাটাবেসে পুনরাবৃত্তি করতে পারেন। যদি বিবৃতিগুলির একটিতে কোনও টেবিল কেটে ফেলা হয় তবে তা খুব খারাপ bad
গ্রেসন

3
@ গ্রেইসন: দুর্দান্ত পয়েন্ট! সত্যিই, আমি সত্যিই এটি সম্পর্কে কখনই চিন্তা না করার জন্য কিছুটা বোবা অনুভব করি। মাঝে মাঝে আমার মনে হয় আমরা যে আর্গুমেন্টগুলি চাই তা ব্যবহার করার এবং বাকী বিষয়টিকে উপেক্ষা করার অভ্যাসে ফেলি!
jkschneider

1
আপনি ডাটাবেস নিয়ন্ত্রণ করেন, নাম পরিবর্তন করবেন কেন?
jkschneider

3
newVersionদয়ালু অপ্রয়োজনীয়, যেমন আপনি সর্বদা নির্ধারকটিতে যে কোনও উপায়ে বর্তমান ডাটাবেস সংস্করণ সেট করে (অংশ 2 দেখুন) এবং এটি সর্বদা মিলবে। এখানে মূল ধারণাটি হ'ল আপনি যে কোনও জায়গা থেকে সরাসরি newVersionঅন্য আপগ্রেড আপগ্রেডের মধ্য দিয়ে পাস না করেই যেখানেই সরাসরি স্ট্রিম করতে চান না ।
jkschneider 12'15

2
@ কাই CREATE_READINGSযুক্তিটি কখনই অনআপগ্রেডে থাকা উচিত নয়, কারণ এটি onCreateআপনার প্রথম সংস্করণের পদ্ধতিতে ছিল । মামলার চিন্তা onUpgradeহিসাবে "আমি থেকে আপগ্রেড করছি সুইচ oldVersion"। আপনি যদি সংস্করণ 1 থেকে আপগ্রেড করে থাকেন তবে আপনি পঠন সারণী তৈরি করতে পারবেন না, কারণ এটি ইতিমধ্যে বিদ্যমান ছিল। আশা করি এটি উপলব্ধি করে ...
jkschneider

9

আপনার কোডটি সঠিক দেখাচ্ছে। আমার পরামর্শ হ'ল ডেটাবেস ইতিমধ্যে মনে করে এটি আপগ্রেড হয়েছে। আপনি যদি সংস্করণ নম্বর বাড়ানোর পরে প্রকল্পটি কার্যকর করেন তবে execSQLকলটি যুক্ত করার আগে আপনার পরীক্ষার ডিভাইস / এমুলেটরটির ডেটাবেস ইতিমধ্যে বিশ্বাস করতে পারে এটি সংস্করণ 2 এ রয়েছে।

এটি যাচাই করার একটি দ্রুত উপায় হ'ল সংস্করণ নম্বরটি 3 এ পরিবর্তন করা হবে - যদি এটির পরে এটি আপগ্রেড হয় তবে আপনি জানেন যে এটি কেবলমাত্র আপনার ডিভাইস বিশ্বাস করেছে যে এটি ইতিমধ্যে আপগ্রেড হয়েছে।


তারপরে, প্রত্যাশা অনুযায়ী, আপনার কোডটি ঠিক ছিল; এটি যখন ক্রমবর্ধমানভাবে চালিত হয়েছিল তখনই নয়। onCreate()টেক্সট সৃষ্টি যুক্ত করে মনে রাখবেন জিক্সনিডারকে নির্দেশিত পছন্দ করতে।
গ্রেইসন

2

আপনি এসকিউএলওপেনহেল্পারের onUpgradeপদ্ধতিটি ব্যবহার করতে পারেন । অন-আপগ্রেড পদ্ধতিতে, আপনি পরামিতিগুলির মধ্যে একটি হিসাবে পুরানো সংস্করণ পান get

ইন onUpgradeব্যবহার switchকরুন এবং প্রতিটি caseগুলি ডাটাবেসের বর্তমান সংস্করণ ট্র্যাক রাখতে সংস্করণ সংখ্যা ব্যবহার করুন।

এটা ভাল যে আপনি থেকে লুপ oldVersionথেকে newVersion, বৃদ্ধিশীল versionএকটি সময়ে 1 এবং তারপর ধাপে ডাটাবেসের পদক্ষেপ আপগ্রেড করতে পারবেন। এটি খুব সহায়ক যখন ডেটাবেস সংস্করণ 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;
    }

}

যদি আপনি এই ব্রেক স্টেটমেন্টগুলি সরিয়ে ফেলেন তবে আপনার লুপের দরকার পড়বে না
তাশ পেমিভা

তবে ওল্ড ভার্সনকে পরের ক্ষেত্রে @ টাশপেমিভা পাস করার জন্য প্রতিটি ক্ষেত্রেই বাড়ানো উচিত
আনা

একটি স্যুইচ স্টেটমেন্টটিতে বিরতি দেওয়ার কারণটি হ'ল একবারে একাধিক মামলা চালানো সম্ভব - এবং মামলার শর্ত পূরণ না হলেও এটিই ঘটবে, @ বেউলাহানা
তাশ পেমহিওয়া

যদি আপনি বিরতি যোগ করেন এবং কিছু ডিবি পুরাতন বা সাম্প্রতিক সংস্করণ রয়েছে তবে আপনার ক্যোয়ারী ব্যর্থ হতে পারে তাই বিরতির প্রয়োজন নেই উদাহরণস্বরূপ কিছু ডিবি সংস্করণে যদি কিছু কলাম ইতিমধ্যে পরিবর্তিত হয় তবে আপনার ক্যোয়ারি ডিবি সংস্করণের ক্ষতির ক্রম অনুসারে ব্যর্থ হতে পারে
নীরজ সিং

2

@ jkschneider এর উত্তর সঠিক। তবে আরও ভাল পদ্ধতির আছে।

Https://riggaroo.co.za/android-sqlite-database-use-onupgrade-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) ;

এই। এসকিএল ফাইলগুলি ডাটাবেসের সংস্করণ অনুযায়ী অনআপগ্রেড () পদ্ধতিতে কার্যকর করা হবে।

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

ডাটাবেস সংস্করণগুলি পরিচালনা করা অ্যাপ্লিকেশন বিকাশের খুব গুরুত্বপূর্ণ অংশ। আমি ধরে নিলাম আপনার ইতিমধ্যে ক্লাস অ্যাপডিবিহেল্পার প্রসারিত রয়েছে SQLiteOpenHelper। আপনি যখন এটি প্রসারিত করবেন তখন আপনার প্রয়োগ onCreateonUpgradeপদ্ধতি প্রয়োজন।

  1. কখন onCreateএবং onUpgradeপদ্ধতিগুলি ডাকা হয়

    • onCreate অ্যাপ্লিকেশন নতুন ইনস্টল করা হলে ডাকা হয়।
    • onUpgrade অ্যাপ্লিকেশন আপডেট হওয়ার পরে বলা হয়।
  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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.