LoginSignup
1
0

More than 1 year has passed since last update.

[Swift] Realmで後からプライマリキーを追加しマイグレーション

Last updated at Posted at 2021-10-16

プライマリキーを後からRealm Objectに追加してマイグレーションする際に、少し手こずったので備忘録します。

Realm Objectクラスにプライマリキーを追加

Before

class Diary: Object {
    @objc dynamic var text: String = ""
    @objc dynamic var createdAt: Date = Date()
}

After

class Diary: Object {
    @objc dynamic var id: String = NSUUID().uuidString // primary key
    @objc dynamic var text: String = ""
    @objc dynamic var createdAt: Date = Date()

    //Primary Keyの設定
    override static func primaryKey() -> String? {
        return "id"
    }
}

追加した箇所

    @objc dynamic var id: String = NSUUID().uuidString // primary key

Realmにはオートインクリメントの機能がないため、プライマリキーを連番の数字にしたい場合は自分で加算するロジックを実装する必要があります。今回は後からプライマリキーを追加するため、既存のデータに対してもidを振る必要があり処理を書くのが色々面倒だと感じました。
その手間を省くため、一意の文字列を生成してくれるUUIDをプライマリキーの初期値に指定しました。
もし作成順でデータが欲しくなった場合はcreatedAtカラムをソートすればいいため、Realmの場合はこの方法がいいかなと思いました。

    //Primary Keyの設定
    override static func primaryKey() -> String? {
        return "id"
    }

こちらの関数でプライマリキーのカラム名を返すことでRealm側がプライマリキーを認識します。

マイグレーション

ユーザーがアップデートした際に、DBの変更を正しく反映するためにマイグレーションが必要です。
起動時に通るAppDelegate.siwftのapplication~~関数で以下のように記述します。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        migration()

        return true
    }

    // Realmマイグレーション処理
    func migration() {
        Realm.Configuration.defaultConfiguration = Realm.Configuration(
            schemaVersion: 1,
            migrationBlock: { migration, oldSchemaVersion in
                if(oldSchemaVersion < 1) {
                    migration.enumerateObjects(ofType: Diary.className()) { oldObject, newObject in
                        newObject!["id"] = NSUUID().uuidString
                    }
                }
            }
        )
    }

RealmのSchema Versionを1へアップデートし既存のデータに対しプライマリキーのUUIDを追加しています。(初期のRealmのSchema Versionは0)

                if(oldSchemaVersion < 1) {
                    migration.enumerateObjects(ofType: Diary.className()) { oldObject, newObject in
                        newObject!["id"] = NSUUID().uuidString
                    }
                }

このif文について
他のサイトでは、カラムの追加と削除をする場合はこちらのifの中身は何も書く必要がなく自動でRealm側が認識してくれると記載がありましたが、僕の環境ではエラーが出ました。
既存データに対しidの初期値を与えることでエラーが消えたため、おそらくプライマリキーを設定したい場合はこのように記述する必要がありそうです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0