স্ক্লাইটের জন্য অ্যাপ্লিকেশন ডাটাবেস স্থানান্তরের সেরা অনুশীলন


96

আমি আমার আইফোনের জন্য স্ক্লাইট ব্যবহার করছি এবং আমি আশা করি সময়ের সাথে সাথে ডেটাবেস স্কিমার পরিবর্তন হতে পারে। প্রতিবার সফল মাইগ্রেশন করার জন্য গোচা, নামকরণের সম্মেলন এবং জিনিসগুলি কী কী?

উদাহরণস্বরূপ, আমি ডাটাবেস নামের (যেমন ডাটাবেস_ভি 1) একটি সংস্করণ যুক্ত করার কথা ভেবেছি।

উত্তর:


114

আমি একটি অ্যাপ্লিকেশন বজায় রাখি যা পর্যায়ক্রমে একটি স্ক্লাইট ডাটাবেস আপডেট করতে এবং পুরানো ডাটাবেসগুলিকে নতুন স্কিমাতে স্থানান্তর করতে হবে এবং আমি এখানে যা করছি তা এখানে:

ডাটাবেস সংস্করণটি ট্র্যাক করার জন্য, আমি স্কেলাইট সরবরাহকারী ইউজার-ভার্সন ভেরিয়েবলটি ব্যবহার করি (স্ক্লাইটটি এই ভেরিয়েবলটির সাথে কিছুই করে না, আপনি দয়া করে এটি ব্যবহার করতে পারবেন)। এটি 0 থেকে শুরু হয় এবং আপনি নিম্নলিখিত স্ক্লাইট স্টেটমেন্টগুলির সাথে এই পরিবর্তনশীলটি পেতে / সেট করতে পারেন:

> PRAGMA user_version;  
> PRAGMA user_version = 1;

অ্যাপ্লিকেশনটি শুরু হয়ে গেলে, আমি বর্তমান ব্যবহারকারী-সংস্করণটি পরীক্ষা করে দেখি, স্কিমাটি টু ডেট আনার জন্য প্রয়োজনীয় যে কোনও পরিবর্তনগুলি প্রয়োগ করি এবং তারপরে ব্যবহারকারী-সংস্করণটি আপডেট করি update আমি কোনও লেনদেনে আপডেটগুলি গুটিয়ে রাখি যাতে কিছু ভুল হয়ে যায়, পরিবর্তনগুলি প্রতিশ্রুতিবদ্ধ হয় না।

স্কিমা পরিবর্তন করার জন্য, স্ক্লাইট কিছু নির্দিষ্ট ক্রিয়াকলাপের জন্য "অল্টার টেবল" সিনট্যাক্স সমর্থন করে (টেবিলটির নাম পরিবর্তন করে বা একটি কলাম যুক্ত করে)। বিদ্যমান টেবিলগুলিকে স্থানে আপডেট করার এটি সহজ উপায়। ডকুমেন্টেশন এখানে দেখুন: http://www.sqlite.org/lang_altertable.html । "ALTER TABLE" সিনট্যাক্স দ্বারা সমর্থিত নয় এমন কলামগুলি বা অন্যান্য পরিবর্তনগুলি মোছার জন্য, আমি একটি নতুন টেবিল তৈরি করেছি, এতে তারিখটি স্থানান্তর করব, পুরাতন টেবিলটি ফেলে দিন এবং নতুন টেবিলটির মূল নাম রাখব।


4
আমি একই যুক্তি রাখার চেষ্টা করছি, তবে কোনও কারণে যখন আমি "প্রগমা ইউজার_ভার্সন =" চালাই? প্রোগ্রামিকভাবে, এটি ব্যর্থ ... কোন ধারণা?
ইউনিকর্ন

7
প্রাগমা সেটিংস প্যারামিটারগুলিকে সমর্থন করে না, আপনাকে আসল মানটি সরবরাহ করতে হবে: "প্রগমা ইউজার_ভার্সন = 1"।
সিজেরো

4
আমার একটা প্রশ্ন আছে. আসুন বলি যে আপনি যদি প্রাথমিক সংস্করণ ১। এবং বর্তমান সংস্করণ 5 হয় তবে সংস্করণ 2,3,4 এ কিছু আপডেট রয়েছে। শেষ ব্যবহারকারী কেবল আপনার সংস্করণ 1 ডাউনলোড করেছেন এবং এখন 5 সংস্করণে আপগ্রেড করেছেন আপনার কী করা উচিত?
বাগসফ্লায়ার

6
ডেটাবেসটি বিভিন্ন পদক্ষেপে আপডেট করুন, সংস্করণ 1 থেকে সংস্করণ 2 তে প্রয়োজনীয় পরিবর্তনগুলি প্রয়োগ করুন, তারপরে সংস্করণ 2 থেকে সংস্করণ 3, ইত্যাদি ... আপডেট না হওয়া অবধি। এটি করার একটি সহজ উপায় হ'ল একটি সুইচ স্টেটমেন্ট যেখানে প্রতিটি "কেস" স্টেটমেন্ট একটি সংস্করণ দ্বারা ডাটাবেস আপডেট করে। আপনি বর্তমান ডাটাবেস সংস্করণে "স্যুইচ করুন" এবং আপডেটটি সম্পূর্ণ না হওয়া পর্যন্ত কেস স্টেটমেন্টগুলি পড়ে যায়। আপনি যখনই ডাটাবেস আপডেট করবেন তখন কেবল একটি নতুন কেস স্টেটমেন্ট যুক্ত করুন। এর বিশদ উদাহরণের জন্য নীচে উত্তরটি বিলি গ্রে দেখুন।
Rngbus

4
@ কনস্ট্যান্টিন টার্কাস, ডকুমেন্টেশন অনুসারে ইউটিলিটি application_idদ্বারা ফাইল ফর্ম্যাট সনাক্তকরণের জন্য অতিরিক্ত কিছু file, উদাহরণস্বরূপ ডাটাবেসের সংস্করণ নয়।
xaizek

30

জাস্ট কৌতুহলের উত্তরটি ডেড-অন (আপনি আমার বক্তব্যটি পেয়েছেন!), এবং এটি বর্তমানে আমরা অ্যাপ্লিকেশনটিতে থাকা ডাটাবেস স্কিমার সংস্করণটি ট্র্যাক করতে ব্যবহার করি।

অ্যাপ্লিকেশনটির প্রত্যাশিত স্কিমা সংস্করণের সাথে মেলে ব্যবহারকারী-রূপান্তর পেতে যে মাইগ্রেশনগুলি হওয়া দরকার সেগুলি চালানোর জন্য, আমরা একটি সুইচ স্টেটমেন্ট ব্যবহার করি। আমাদের অ্যাপ স্ট্রিপটিতে এটি দেখতে কেমন লাগে তার একটি কাট-আপ উদাহরণ এখানে :

- (void) migrateToSchemaFromVersion:(NSInteger)fromVersion toVersion:(NSInteger)toVersion { 
    // allow migrations to fall thru switch cases to do a complete run
    // start with current version + 1
    [self beginTransaction];
    switch (fromVersion + 1) {
        case 3:
            // change pin type to mode 'pin' for keyboard handling changes
            // removing types from previous schema
            sqlite3_exec(db, "DELETE FROM types;", NULL, NULL, NULL);
            NSLog(@"installing current types");
            [self loadInitialData];
        case 4:
            //adds support for recent view tracking
            sqlite3_exec(db, "ALTER TABLE entries ADD COLUMN touched_at TEXT;", NULL, NULL, NULL);
        case 5:
            {
                sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN image TEXT;", NULL, NULL, NULL);
                sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN entry_count INTEGER;", NULL, NULL, NULL);
                sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_id_idx ON categories(id);", NULL, NULL, NULL);
                sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_name_id ON categories(name);", NULL, NULL, NULL);
                sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS entries_id_idx ON entries(id);", NULL, NULL, NULL);

               // etc...
            }
    }

    [self setSchemaVersion];
    [self endTransaction];
}

4
আচ্ছা, আমি দেখিনি আপনি কোথায় toVersionআপনার কোড ব্যবহার করেন? আপনি 0 সংস্করণে থাকলে কীভাবে এটি পরিচালনা করা হয় এবং এর পরে আরও দুটি সংস্করণ রয়েছে। এর অর্থ আপনাকে 0 থেকে 1 এবং 1 থেকে 2 পর্যন্ত স্থানান্তর করতে হবে আপনি কীভাবে এটি পরিচালনা করেন?
শে

4
@ কনফিলে কোনও breakবিবৃতি নেই switch, সুতরাং পরবর্তী সমস্ত স্থানান্তরও ঘটবে।
ম্যাট

স্ট্রিপ লিঙ্কটি বিদ্যমান নেই
পেড্রো লুজ

20

আমাকে এফএমডিবি এবং এমবিপ্রোগ্রেসএইচডির সাথে কিছু স্থানান্তর কোড ভাগ করে নেওয়া যাক।

এখানে আপনি কীভাবে স্কিমা সংস্করণ নম্বরটি পড়েন এবং লিখবেন (এটি সম্ভবত একটি মডেল শ্রেণীর অংশ, আমার ক্ষেত্রে এটি ডেটাবেস নামে একটি সিঙ্গলটন ক্লাস):

- (int)databaseSchemaVersion {
    FMResultSet *resultSet = [[self database] executeQuery:@"PRAGMA user_version"];
    int version = 0;
    if ([resultSet next]) {
        version = [resultSet intForColumnIndex:0];
    }
    return version;
}

- (void)setDatabaseSchemaVersion:(int)version {
    // FMDB cannot execute this query because FMDB tries to use prepared statements
    sqlite3_exec([self database].sqliteHandle, [[NSString stringWithFormat:@"PRAGMA user_version = %d", DatabaseSchemaVersionLatest] UTF8String], NULL, NULL, NULL);
}

[self database]অলসভাবে ডেটাবেস খোলে এমন পদ্ধতি এখানে :

- (FMDatabase *)database {
    if (!_databaseOpen) {
        _databaseOpen = YES;

        NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *databaseName = [NSString stringWithFormat:@"userdata.sqlite"];

        _database = [[FMDatabase alloc] initWithPath:[documentsDir stringByAppendingPathComponent:databaseName]];
        _database.logsErrors = YES;

        if (![_database openWithFlags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FILEPROTECTION_COMPLETE]) {
            _database = nil;
        } else {
            NSLog(@"Database schema version is %d", [self databaseSchemaVersion]);
        }
    }
    return _database;
}

এবং এখানে ভিউ কন্ট্রোলার থেকে মাইগ্রেশন পদ্ধতিগুলি ডাকা হয়েছে:

- (BOOL)databaseNeedsMigration {
    return [self databaseSchemaVersion] < databaseSchemaVersionLatest;
}

- (void)migrateDatabase {
    int version = [self databaseSchemaVersion];
    if (version >= databaseSchemaVersionLatest)
        return;

    NSLog(@"Migrating database schema from version %d to version %d", version, databaseSchemaVersionLatest);

    // ...the actual migration code...
    if (version < 1) {
        [[self database] executeUpdate:@"CREATE TABLE foo (...)"];
    }

    [self setDatabaseSchemaVersion:DatabaseSchemaVersionLatest];
    NSLog(@"Database schema version after migration is %d", [self databaseSchemaVersion]);
}

এবং এখানে রুট ভিউ কন্ট্রোলার কোডটি মাইগ্রেশনকে অনুরোধ করে একটি অগ্রগতি বেজেল প্রদর্শন করতে এমবিপ্রোগ্রেসএইচডি ব্যবহার করে:

- (void)viewDidAppear {
    [super viewDidAppear];
    if ([[Database sharedDatabase] userDatabaseNeedsMigration]) {
        MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view.window];
        [self.view.window addSubview:hud];
        hud.removeFromSuperViewOnHide = YES;
        hud.graceTime = 0.2;
        hud.minShowTime = 0.5;
        hud.labelText = @"Upgrading data";
        hud.taskInProgress = YES;
        [[UIApplication sharedApplication] beginIgnoringInteractionEvents];

        [hud showAnimated:YES whileExecutingBlock:^{
            [[Database sharedDatabase] migrateUserDatabase];
        } onQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) completionBlock:^{
            [[UIApplication sharedApplication] endIgnoringInteractionEvents];
        }];
    }
}

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

"ব্যবহারকারীর রূপান্তর" ফিরিয়ে দেওয়ার জন্য আপনি কেন "সেটডেটাবেসসিমা ভার্সন" পদ্ধতি ব্যবহার করেন? "ইউজার_ভার্সন" এবং "স্কিমা_ভার্সন" আমার মনে হয় এমন দুটি ভিন্ন প্রগমা।
পল ব্রউভেসিনস্কি

@ পলব্রেউক্রাইন্স্কি যেহেতু আমি সাধারণত ব্যবহৃত শর্তাদি পছন্দ করি, এসকিউএলাইট পদগুলি নয়, এবং এটি এটাকে বলে যাচ্ছি (আমার ডাটাবেস স্কিমার সংস্করণ)। আমি এই ক্ষেত্রে schema_versionএসকিউএলাইট -নির্দিষ্ট শর্তাদি সম্পর্কে চিন্তা করি না, এবং প্রাগমা সাধারণত লোকেরা হয় এমন কিছু নয়।
আন্দ্রে তারানসভ

আপনি লিখেছেন: // এফএমডিবি এই কোয়েরিটি কার্যকর করতে পারে না কারণ এফএমডিবি প্রস্তুত বিবৃতি ব্যবহার করার চেষ্টা করে। আপনি এই দ্বারা কি বোঝাতে চেয়েছেন? এটির কাজ করা উচিত: এনএসএসআরিং * ক্যোয়ারী = [এনএসএস স্ট্রিং উইথফর্ম্যাট: @ "PRAGMA USER_VERSION =% i", ব্যবহারকারী সংস্করণ]; [_ডিবি এক্সিকিউটআপডেট: ক্যোয়ারী]; : এখানে উল্লেখ হিসাবে stackoverflow.com/a/21244261/1364174
পল Brewczynski

4
(উপরের আমার মন্তব্যের সাথে সম্পর্কিত) দ্রষ্টব্য: এফএমডিবি লাইব্রেরিতে এখন বৈশিষ্ট্য রয়েছে: ইউজারভার্শন এবং সেট ইউজারভার্সন: পদ্ধতিগুলি! সুতরাং আপনাকে Verbose @ Andrey Taransov এর পদ্ধতিগুলি ব্যবহার করতে হবে না: - (অবধি) ডাটাবেসচেমা ভার্সন! এবং (অকার্যকর) সেট ডেটাবেসসিমা ভার্সন: (ইনট) সংস্করণ। এফএমডিবি ডকুমেন্টেশন: ccgus.github.io/fmdb/html/ ক্যাটাগরিস/… :
পল ব্রেভজিনস্কি

4

এসএমএলাইট আপগ্রেড ফ্রেমওয়ার্ক তৈরি করাই সেরা সমাধান আইএমও। আমার একই সমস্যা ছিল (সি # ওয়ার্ল্ডে) এবং আমি আমার নিজস্ব কাঠামোটি তৈরি করেছি। আপনি এটি সম্পর্কে এখানে পড়তে পারেন । এটি নিখুঁতভাবে কাজ করে এবং আমার (পূর্ববর্তী স্বপ্নদোষ) আপগ্রেডগুলি আমার পক্ষে সর্বনিম্ন প্রচেষ্টা সহ কাজ করে।

যদিও লাইব্রেরিটি সি # তে কার্যকর করা হয়েছে, সেখানে উপস্থাপিত ধারণাগুলি আপনার ক্ষেত্রেও কার্যকর হবে।


এটি একটি দুর্দান্ত সরঞ্জাম; খুব খারাপ এটি নিখরচায়
মিহাই দামিয়ান

4

1/migrationsএসকিউএল-ভিত্তিক মাইগ্রেশনগুলির তালিকা সহ ফোল্ডার তৈরি করুন , যেখানে প্রতিটি মাইগ্রেশন এরকম কিছু দেখায়:

/migrations/001-categories.sql

-- Up
CREATE TABLE Category (id INTEGER PRIMARY KEY, name TEXT);
INSERT INTO Category (id, name) VALUES (1, 'Test');

-- Down
DROP TABLE User;

/migrations/002-posts.sql

-- Up
CREATE TABLE Post (id INTEGER PRIMARY KEY, categoryId INTEGER, text TEXT);

-- Down
DROP TABLE Post;

2। প্রয়োগকৃত স্থানান্তরগুলির তালিকা সহ ডিবি টেবিল তৈরি করুন, উদাহরণস্বরূপ:

CREATE TABLE Migration (name TEXT);

3। অ্যাপ্লিকেশন বুটস্ট্র্যাপ যুক্তি আপডেট করুন যাতে এটি শুরু হওয়ার আগে, এটি থেকে মাইগ্রেশনগুলির তালিকাটি ধরে ফেলে/migrations ফোল্ডারটি চালিত করে যা এখনও প্রয়োগ হয়নি।

এখানে জাভাস্ক্রিপ্ট প্রয়োগ করা একটি উদাহরণ রয়েছে: নোড.জেএস অ্যাপসের জন্য এসকিউএলাইট ক্লায়েন্ট


2

কিছু টিপস...

1) আমি আপনার ডেটাবেসটিকে একটি এনএসওপরেশনে মাইগ্রেট করতে এবং ব্যাকগ্রাউন্ড থ্রেডে চালানোর জন্য সমস্ত কোড রাখার পরামর্শ দিচ্ছি। ডাটাবেস স্থানান্তরিত হওয়ার সময় আপনি কোনও স্পিনারের সাথে একটি কাস্টম ইউআইএলার্টভিউ প্রদর্শন করতে পারেন।

২) নিশ্চিত হয়ে নিন যে আপনি অ্যাপ্লিকেশনটির নথিতে বান্ডেল থেকে আপনার ডাটাবেসটি অনুলিপি করছেন এবং সেই অবস্থান থেকে এটি ব্যবহার করছেন, অন্যথায় আপনি কেবলমাত্র প্রতিটি অ্যাপ্লিকেশন আপডেটের সাথে পুরো ডাটাবেসটি ওভাররাইট করবেন এবং তারপরে নতুন খালি ডাটাবেসটি স্থানান্তরিত করবেন।

3) এফএমডিবি দুর্দান্ত, তবে এর এক্সিকিউটিউকুয়ের পদ্ধতিটি কোনও কারণে PRAGMA কোয়েরি করতে পারে না। আপনি PRAGMA ব্যবহারকারীর রূপান্তর ব্যবহার করে স্কিমা সংস্করণটি পরীক্ষা করতে চাইলে আপনার নিজের পদ্ধতিটি লিখতে হবে যা সরাসরি স্ক্লাইট 3 ব্যবহার করে।

৪) এই কোড কাঠামোটি নিশ্চিত করে যে আপনার আপডেটগুলি যথাযথভাবে কার্যকর করা হয়েছে এবং সমস্ত আপডেট কার্যকর করা হয়, ব্যবহারকারী অ্যাপ্লিকেশন আপডেটগুলির মধ্যে কতক্ষণ যান না কেন। এটি আরও রিফ্যাক্টর করা যেতে পারে তবে এটি দেখার খুব সহজ উপায় way আপনার ডেটা সিঙ্গেলটন তাত্ক্ষণিক প্রতিযোগিতায় প্রতিবার এই পদ্ধতিটি নিরাপদে চালানো যেতে পারে, এবং কেবলমাত্র একটি ছোট ডিবি ক্যোয়ারির জন্য ব্যয় হয় যা আপনি নিজের ডেটা সিঙ্গেলটন সঠিকভাবে সেট আপ করলে সেশনে প্রতি একবার হয়।

- (void)upgradeDatabaseIfNeeded {
    if ([self databaseSchemaVersion] < 3)
    {
        if ([self databaseSchemaVersion] < 2)
        {
            if ([self databaseSchemaVersion] < 1)
            {
                // run statements to upgrade from 0 to 1
            }
            // run statements to upgrade from 1 to 2
        }
        // run statements to upgrade from 2 to 3

        // and so on...

        // set this to the latest version number
        [self setDatabaseSchemaVersion:3];
    }
}

1

আপনি যদি ডাটাবেস স্কিমা এবং এটি লকস্টেপ ব্যবহার করে এমন সমস্ত কোড পরিবর্তন করেন যা এম্বেড করা এবং ফোন-ভিত্তিক অ্যাপ্লিকেশনগুলির ক্ষেত্রে যেমন হয়, সমস্যাটি আসলে নিয়ন্ত্রণের মধ্যে রয়েছে (কোনও স্বপ্নের সাথে তুলনীয় কিছুই না যে কোনও এন্টারপ্রাইজ ডিবিতে স্কিমা স্থানান্তরিত হয়) এটি কয়েকশো অ্যাপ্লিকেশন পরিবেশন করতে পারে - সমস্তই ডিবিএর নিয়ন্ত্রণে নয় ;-)।


0

। নেট এর জন্য আপনি লিব ব্যবহার করতে পারেন:

সত্তা ফ্রেমওয়ার্ককোর.স্ক্লাইট.মাইগ্রেশন

এটি সহজ, সুতরাং অন্য যে কোনও প্ল্যাটফর্মের জন্য আপনি খুব সহজেই একই আচরণ ব্যবহার করতে পারেন b

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