রুমে ডাটাবেস স্থানান্তর যদি কেবল নতুন টেবিল যুক্ত হয়


107

ধরে নেওয়া যাক না, আমার কাছে একটি সাধারণ রুম ডাটাবেস রয়েছে:

@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
    public abstract Dao getDao();
}

এখন, আমি একটি নতুন সত্তা যুক্ত করছি: Petএবং সংস্করণটিকে 2 তে বাম্পিং করছি :

@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
    public abstract Dao getDao();
}

অবশ্যই, রুম একটি ব্যতিক্রম ছুঁড়েছে: java.lang.IllegalStateException: A migration from 1 to 2 is necessary.

ধরে নিচ্ছি, আমি Userক্লাস পরিবর্তন করি নি (তাই সমস্ত ডেটা নিরাপদ), আমাকে মাইগ্রেশন সরবরাহ করতে হবে যা কেবল একটি নতুন টেবিল তৈরি করে। সুতরাং, আমি রুম দ্বারা উত্পন্ন উত্সগুলি সম্পর্কে অনুসন্ধান করছি, আমার নতুন টেবিলটি তৈরি করতে উত্পন্ন জিজ্ঞাসাটি অনুসন্ধান করছি, এটি অনুলিপি করছি এবং মাইগ্রেশনে আটকানো হয়েছে:

final Migration MIGRATION_1_2 =
        new Migration(1, 2) {
            @Override
            public void migrate(@NonNull final SupportSQLiteDatabase database) {
                database.execSQL("CREATE TABLE IF NOT EXISTS `Pet` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))");
            }
        };

তবে আমি ম্যানুয়ালি এটি করা অসুবিধাজনক মনে করি। রুমকে বলার কোনও উপায় আছে: আমি বিদ্যমান টেবিলের কোনওটির সাথেও স্পর্শ করছি না, তাই ডেটা নিরাপদ। আমার জন্য মাইগ্রেশন তৈরি করুন?


আপনি এই একটি সমাধান খুঁজে পেয়েছেন?
মিক্কেল লারসেন

4
আমার একই সমস্যা ছিল এবং এটি আপনি ঠিক একইভাবে ঠিক করেছিলেন এবং এর সমাধানও আমি পাইনি। খুশি আমি তখন একা নই। :)
মিক্কেল লারসেন


4
আমি এই জাতীয় বৈশিষ্ট্যটির জন্য এতটা দেব ... মাইগ্রেশন এবং ফলব্যাক প্রক্রিয়াটি মিশ্রিত
করাও ভাল লাগবে

4
আমি নিশ্চিত না এটি কার্যকর হবে কিনা তবে রুমের কাছে একটি JSON ফাইলে ডাটাবেস স্কিমা রফতানি করার বিকল্প রয়েছে। ডেভেলপার.অ্যান্ড্রয়েড / ট্রেনিং / ডেটা- স্টোরেজ / রুম / স্পষ্টত এর অর্থ হ'ল ম্যানুয়ালি মাইগ্রেশন স্ক্রিপ্ট যুক্ত করা হবে তবে আপনার এসকিউএল স্টেটমেন্ট পাওয়ার জন্য আপনাকে স্বয়ংক্রিয়ভাবে উত্পন্ন ক্লাসগুলির মধ্য দিয়ে রুট করার প্রয়োজন হবে না।
জেমস লেন্ড্রেম

উত্তর:


84

রুম নেই না অন্তত পর্যন্ত একটি ভাল মাইগ্রেশন সিস্টেম আছে, 2.1.0-alpha03

সুতরাং, যতক্ষণ না আমাদের আরও ভাল মাইগ্রেশন সিস্টেম রয়েছে, ততক্ষণে রুমে সহজভাবে মাইগ্রেশন করার জন্য কিছু কার্যক্রম রয়েছে।

যেহেতু @Database(createNewTables = true) বা যেমন MigrationSystem.createTable(User::class), যেখানে এক বা অন্য হওয়া উচিত সেখানে কোনও পদ্ধতি নেই , একমাত্র সম্ভাব্য পথ চলছে

CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))

আপনার migrateপদ্ধতির ভিতরে ।

val MIGRATION_1_2 = object : Migration(1, 2){
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))")
    }
}

এসকিউএল স্ক্রিপ্টের উপরে উঠতে আপনার কাছে 4 টি উপায় রয়েছে

1. নিজের দ্বারা লিখুন

মূলত, আপনাকে উপরের স্ক্রিপ্টটি লিখতে হবে যা ঘরটি তৈরি করা স্ক্রিপ্টটির সাথে মিলবে। এই উপায় সম্ভব, সম্ভাব্য নয়। (আপনার 50 টি ক্ষেত্র রয়েছে তা বিবেচনা করুন)

2. রফতানি স্কিমা

আপনি যদি exportSchema = trueআপনার @Databaseটীকাটির অন্তর্ভুক্ত করেন , ঘরটি আপনার প্রকল্প ফোল্ডারের / স্কিমার মধ্যে ডাটাবেস স্কিমা তৈরি করবে। ব্যবহার হয়

@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
   //...
}

নিশ্চিত হয়ে নিন যে আপনি build.gradeনিজের অ্যাপ্লিকেশন মডিউলটির নীচে লাইন অন্তর্ভুক্ত করেছেন

kapt {
    arguments {
        arg("room.schemaLocation", "$projectDir/schemas".toString())
    }
} 

আপনি যখন প্রকল্পটি চালাবেন বা নির্মাণ করবেন আপনি একটি জেএসওএন ফাইল পাবেন 2.json, এতে আপনার রুমের ডাটাবেসের মধ্যে সমস্ত প্রশ্ন রয়েছে।

  "formatVersion": 1,
  "database": {
    "version": 2,
    "identityHash": "325bd539353db508c5248423a1c88c03",
    "entities": [
      {
        "tableName": "User",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, PRIMARY KEY(`id`))",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },

সুতরাং, আপনি createSqlআপনার migrateপদ্ধতির মধ্যে উপরেরটি অন্তর্ভুক্ত করতে পারেন ।

৩. অ্যাপড্যাটাস ডাটা_আইএমপিএল থেকে কোয়েরি পান

আপনি যদি স্কিমা রফতানি করতে না চান তবে আপনি প্রকল্পটি চালিয়ে বা বিল্ডিং করে কোয়েরিটি পেতে পারেন যা AppDatabase_Impl.javaফাইল উত্পন্ন করবে । এবং নির্দিষ্ট ফাইলের মধ্যে আপনার থাকতে পারে।

@Override
public void createAllTables(SupportSQLiteDatabase _db) {
  _db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");

createAllTablesপদ্ধতির মধ্যে , সমস্ত সত্তার তৈরি স্ক্রিপ্টগুলি থাকবে। আপনি এটি পেতে পারেন এবং আপনার migrateপদ্ধতির মধ্যে অন্তর্ভুক্ত করতে পারেন ।

৪. টিকা প্রক্রিয়াকরণ।

আপনি অনুমান করতে পারে, রুম এর উপরে উল্লিখিত সব উত্পন্ন schema, এবং AppDatabase_Implসংকলন সময়ের মধ্যে ও টীকার প্রসেসিং ফাইল যা আপনার সাথে যোগ

kapt "androidx.room:room-compiler:$room_version"

তার অর্থ আপনি একই কাজটি করতে পারেন এবং আপনার নিজস্ব এনোটেশন প্রক্রিয়াকরণ লাইব্রেরি তৈরি করতে পারেন যা আপনার জন্য প্রয়োজনীয় সমস্ত তৈরি প্রশ্ন তৈরি করে।

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

  1. একটি নতুন StringBuilderতৈরি করুন এবং "উপস্থিত না থাকলে টেবিল তৈরি করুন" যুক্ত করুন
  2. ক্ষেত্র থেকে class.simplenameবা tableNameক্ষেত্রের দ্বারা সারণির নাম পান @Entity। এটি আপনার যুক্ত করুনStringBuilder
  3. তারপরে আপনার শ্রেণীর প্রতিটি ক্ষেত্রের জন্য এসকিউএল এর কলাম তৈরি করুন। ক্ষেত্রের নাম বা টাইপ করুন, ক্ষেত্রটি নিজেই বা @ColumnInfoটীকা দ্বারা n প্রতিটি ক্ষেত্রের জন্য, আপনাকে নিজের id INTEGER NOT NULLকলামের স্টাইল যুক্ত করতে হবে StringBuilder
  4. এর মাধ্যমে প্রাথমিক কী যুক্ত করুন @PrimaryKey
  5. যোগ করুন ForeignKeyএবং Indicesযদি উপস্থিত থাকে।
  6. শেষ করার পরে এটিকে স্ট্রিংয়ে রূপান্তর করুন এবং এটি ব্যবহার করতে চান এমন কোনও নতুন শ্রেণিতে সংরক্ষণ করুন। উদাহরণস্বরূপ, নীচের মত এটি সংরক্ষণ করুন
public final class UserSqlUtils {
  public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}

তারপরে, আপনি এটি হিসাবে ব্যবহার করতে পারেন

val MIGRATION_1_2 = object : Migration(1, 2){
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL(UserSqlUtils().createTable)
    }
}

আমি নিজের জন্য এমন একটি লাইব্রেরি তৈরি করেছি যা আপনি যাচাই করতে পারেন, এমনকি এটি আপনার প্রকল্পেও ব্যবহার করতে পারেন। মনে রাখবেন যে আমি যে লাইব্রেরিটি তৈরি করেছি তা পূর্ণ নয় এবং এটি কেবল সারণী তৈরির জন্য আমার প্রয়োজনীয়তা পূরণ করে।

ভাল অভিবাসনের জন্য রুমএক্সটেনশন

রুমএক্সটেনশন ব্যবহার করে এমন অ্যাপ্লিকেশন

আশা করি এটি কার্যকর ছিল।

হালনাগাদ

এই উত্তরটি লেখার সময়, রুম সংস্করণ ছিল 2.1.0-alpha03এবং আমি বিকাশকারীদের ইমেল করার সময় আমি এর প্রতিক্রিয়া পেয়েছিলাম

এটিতে আরও ভাল মাইগ্রেশন সিস্টেম থাকবে বলে আশা করা হচ্ছে 2.2.0

দুর্ভাগ্যক্রমে, আমাদের এখনও আরও ভাল মাইগ্রেশন সিস্টেমের অভাব রয়েছে।


4
আপনি যে জায়গাগুলিতে যেখানে পড়েন সেদিকে ইঙ্গিত করতে পারেন ২.২.x কক্ষে আরও ভাল স্থানান্তর হবে? এই দাবিটি করার মতো কোনও কিছুই আমি খুঁজে পাচ্ছি না এবং যেহেতু আমরা বর্তমানে ২.১.০ বিটাতে কাজ করছি, ২.২.০-এ যা আছে তা এই মুহূর্তে অজানা বলে মনে হচ্ছে।
jkane001

4
@ jkane001 আমি ঘরের বিকাশকারীদের একজনকে ইমেল করেছি এবং তাতে সাড়া পেয়েছি।
২.২.x

4
বর্তমানে সংস্করণ ২.২.২ এ এবং এখনও আরও ভাল মাইগ্রেশন নেই :( তবে এটি একটি দুর্দান্ত উত্তর এবং
এটির

@ অ্যান্ড্রয়েড ডেভেলপার # 4 ব্যতীত যা এনোটেশন প্রক্রিয়াজাতকরণ
মুসোফ

4
@ মুসুফ আমি আসলে টেবিলের সৃষ্টি যুক্ত করা ঠিক মনে করি। "CreateAllTables" ফাংশন থেকে কোড অনুলিপি করা সবচেয়ে নিরাপদ উপায়।
অ্যান্ড্রয়েড বিকাশকারী

5

দুঃখিত, ঘর নষ্ট হওয়া ছাড়া টেবিলগুলির স্বতঃ-উত্পাদন সমর্থন করে না।

মাইগ্রেশন লিখতে বাধ্যতামূলক। অন্যথায়, এটি সমস্ত ডেটা মুছে ফেলবে এবং নতুন টেবিল কাঠামো তৈরি করবে।


0

আপনি এইভাবে করতে পারেন-

@Database(entities = {User.class, Pet.class}, version = 2)

abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
public abstract Dao getPetDao();
}

আপনি উপরে উল্লিখিত মত বাকী থাকবে

 db = Room.databaseBuilder(this, AppDatabase::class.java, "your_db")
        .addMigrations(MIGRATION_1_2).build()

রেফারেন্স - আরও জন্য


0

আপনি নীচের গ্রেড কমান্ডটি আপনার ডিফল্ট কনফিগ-এ আপনার অ্যাপ্ল্যাডে যোগ করতে পারেন:

javaCompileOptions {
        annotationProcessorOptions {
            arguments = ["room.schemaLocation":
                                 "$projectDir/schemas".toString()]
        }
    }

আপনি যখন এটি চালান এটি তাদের প্রাসঙ্গিক ক্রেবল টেক্সট স্টেটমেন্টের সাথে টেবিলের নামের একটি তালিকা তৈরি করবে যা থেকে আপনি কেবল নিজের স্থানান্তর অবজেক্টগুলিতে অনুলিপি করে কপি করতে পারবেন। আপনাকে টেবিলের নামগুলি পরিবর্তন করতে হতে পারে।

উদাহরণস্বরূপ এটি আমার উত্পন্ন স্কিমা থেকে:

"tableName": "assets",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `base` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`asset_id`))"

এবং তাই আমি ক্রেডিটএসকিউএল স্টেটমেন্টটি অনুলিপি করেছি এবং '$ {TABLE_NAME}' কে টেবিলের নাম হিসাবে 'সম্পত্তিতে' পরিবর্তন করব এবং ভয়েলা স্বয়ংক্রিয়ভাবে উত্পন্ন ঘর তৈরির বিবরণী।


-1

এই ক্ষেত্রে, আপনাকে কোনও স্থানান্তর করার দরকার নেই, আপনি ডাটাবেস উদাহরণ তৈরি করার সময় .FallbackToDestructiveMigration () কল করতে পারেন।

উদাহরণ:

    instance = Room.databaseBuilder(context, AppDatabase.class, "database name").fallbackToDestructiveMigration().build();

এবং ডাটাবেস সংস্করণ পরিবর্তন করতে ভুলবেন না।


এই সমাধানটি বিদ্যমান সারণীগুলি থেকে আমার সমস্ত ডেটা সরিয়ে ফেলবে।
পাইটর আলেকসান্দার চ্যামিলোভস্কি

দুর্ভাগ্যবশত হ্যাঁ. "ক্রাশ হওয়ার পরিবর্তে ডাটাবেসটিকে পুনরায় তৈরি করতে এই আচরণটি পরিবর্তন করতে আপনি এই পদ্ধতিটি কল করতে পারেন Note নোট করুন যে এটি রুম দ্বারা পরিচালিত ডাটাবেস সারণীর সমস্ত ডেটা মুছে ফেলবে" "
rudicjovan

-2

হতে পারে এই ক্ষেত্রে (আপনি যদি কেবল অন্যদের পরিবর্তন না করে কেবল নতুন টেবিল তৈরি করেছেন) আপনি এটি কোনও মাইগ্রেশন তৈরি না করেই করতে পারেন?


4
না, এই ক্ষেত্রে ঘরটি লগগুলিতে নিক্ষেপ করে: java.lang.IllegalStateException: {old_version from থেকে {new_version} এ স্থানান্তর করা প্রয়োজন
ম্যাক্স মেকিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.