LoginSignup
80
69

More than 5 years have passed since last update.

Realmでプライマリキーをauto incrementっぽく作る

Last updated at Posted at 2015-12-03

アプリ道場 Advent Calendar 2015の4日目は、こたら@kotala_bです。
Realmのプライマリキーの作り方について書いていきます。

プライマリキーって?

プライマリキーというのはOracleやMySqlといったリレーショナルデータベース(RDBMS)で使われている、一意性を保証するためのものです。
Realmでももちろんこのプライマリキーを設定できます。
Realmでプライマリキーを設定するにはこのようにします。

class Person: Object {
    dynamic var id: Int = 0
    dynamic var name: String = ""
    
    override static func primaryKey() -> String? {
        return "id"
    } 
}

RDBMSにはauto incrementと言って、プライマリキーに入れる一意性のある値を自動的に作ってくれる機能があるのですが、Realmにはありません。(v0.96.2時点)
なので、Realmではプライマリキーに入れる値を作る仕組みを自分で用意しなければなりません。

Realmのプライマリキーを作る

プライマリキーの作り方の1つとして「0から順に数値を採番し、保存されているプライマリキーの最大値に+1した値を新しいプライマリキーとして設定する」というような作り方が考えられます。

class MyRealm {
    
    var maxId: Int { return try! Realm().objects(Person).sorted("id").last?.id ?? 0 }
    
    func createNewPerson(name: String) {
        
        let person = Person()
        person.id = maxId + 1
        person.name = name
        
        let realm = try! Realm()
        try! realm.write{ realm.add(person) }
    }
}

上のコードでは、複数のスレッドで実行したときに正しく採番されない可能性があります。
それにmaxIdがふられてるデータを削除したら次に作ったデータにまた同じidがふられたりもするので、プライマリキーの採番を別のところで管理しないといけません。
ちょっと面倒くさそうです。

スレッドセーフなプライマリキーを作る

じゃあどうするの?ってことなんですけど、UUIDを使います。
UUIDというのは、

先人たちはUUIDという便利なものを用意してくれてCocoaにもしっかりと用意されているので、iOS、Objective-C、Swiftで識別子を作りたいときはこれを使いましょう
http://qiita.com/mo_to_44/items/9e41b6aba0c6898d373d

UUIDを都度生成すれば、複数スレッドで実行していても問題ありません。
プライマリキーにUUIDを使うとなると、連番ではなくなり、型もIntではなくなるのでそこだけは注意が必要です。
はじめのコードをUUIDを使ったカタチに書き直すとこうなります。

class Person: Object {
    dynamic var id: String = ""
    dynamic var name: String = ""
    
    override static func primaryKey() -> String? {
        return "id"
    }   
}

class MyRealm {    

    func createNewPerson(name: String) {
        
        let person = Person()
        person.id = NSUUID().UUIDString
        person.name = name
        
        let realm = try! Realm()
        try! realm.write{ realm.add(person) }
    }
}

var maxIdはもういらなくなりました。

auto incrementっぽくする

もう少しauto incrementっぽくするために、プロパティのデフォルト値にNSUUID().UUIDStringを設定するようにします。

class Person: Object {
    dynamic var id: String = NSUUID().UUIDString
    dynamic var name: String = ""
    
    override static func primaryKey() -> String? {
        return "id"
    }
    
}

class MyRealm {
    
    func createNewPerson(name: String) {
        
        let person = Person()
        person.name = name
        
        let realm = try! Realm()
        try! realm.write{ realm.add(person) }
    }
}

これでだいぶauto incrementっぽくプライマリキーを作ってる感じがしてきました。

まとめ

今個人で作っているアプリの中でRealmを使っているんですが、プライマリキーはただ単にユニークな値であればよかったのでUUIDを使った方法を採用しました。

プライマリキーを連番で作るにはいろいろと心配事があって、少し面倒くさそうに感じました。
UUIDであれば特に細かいことを気にする必要はないかなと感じています。

今回試したみたコードはこちらにあります。
https://github.com/kotalab/RealmAutoIncrement

参考

80
69
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
80
69