35657


RealmにてPrimaryキーを書き換えようとしています。  
それによってTableViewの並べ替えをしたいと考えております。  
しかし以下のコードではプライマリーキーのIDを書き換える時にエラーが出ます。

[code]

    Terminating app due to uncaught exception 'RLMException', reason: 'Primary key can't be changed after an object is inserted.'
    
[/code]

エラーメッセージと公式サイトの情報から推察すると、プライマリーキーは変更できないという理解でよろしいでしょうか？

できないとすると、一般的には一度すべてのデータ（多くても数十件のデータを想定）を避難して、DBをすべて削除し採番し直して追加ということで対処するのがいいのでしょうか。  
もしくは、テーブルに表示順を持たせて、それを書き換えるのがいいのでしょうか。

ご教授いただけないでしょうか。  
よろしくお願いいたします。

※以下のコードは、間違いがあるかもしれませんので、したいことを理解する目的で参考にしていただければと思います。

[code]

    //メインデータ
    class mainDataTable: Object {
        dynamic var ID = Int()
        let Days = List<subDataTable>() //LinkingObjects(fromType: subDataTable.self, property: "Day") //
        dynamic var CategoryNo = Int()
        override static func primaryKey() -> String? {
            return "ID"
        }
    }
    
    let realm = try! Realm()
    let results = try! Realm().objects(mainDataTable.self).sorted(byKeyPath: "ID")
    
    override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        //元の位置のデータを控える
        let targetTitle = results[sourceIndexPath.row]
        //編集開始
        realm.beginWrite()
        //Key(ID)が重複しないように元のデータの削除
        realm.delete(results[sourceIndexPath.row])
        //リナンバー
        if sourceIndexPath.row < destinationIndexPath.row {
            for i in sourceIndexPath.row..<destinationIndexPath.row {
                let target = results[i]
                target.ID = i + 1    //ここでエラー
                realm.add(target, update: true)
            }
        } else {
            for i in destinationIndexPath.row..<sourceIndexPath.row {
                let target = results[i]
                target.ID = i - 1　　　//ここでエラー
                realm.add(target, update: true)
            }
        }
        //移動後のナンバーに変更して追加する
        targetTitle.ID = destinationIndexPath.row + 1
        realm.add(targetTitle, update: true)
        //確定
        try! realm.commitWrite()
    }
    
[/code]


CC BY-SA 3.0
2017-06-17T01:47:05.437
35653
2019-11-28T15:09:12.910
2017-06-17T04:29:01.080
5519
10845
question
swift xcode swift3 realm
Realmをデータソースにしてテーブルビューの並べ替えをしたい


Realmに限らず一般的なデータベースは並び順を保持しないので、意図した順で表示するためには順序を示すカラムを定義し、そのカラムでソートして表示します。並べ替えを行うには、順序を示すカラムを更新します。

下記はRealmとUITableViewを用いて同様のことを行うサンプルコードです。

<https://gist.github.com/kishikawakatsumi/cc4a1f32fb8ee34eb509d54027d731b5>

[code]

    class Data: Object {
        dynamic var name = ""
        ...
    
        dynamic var order = 0 // 並べ替えのためのカラムが必要
    }
    
[/code]

上記のように並べ替えに使用するプロパティを追加し、並べ替えのときに呼ばれるメソッドにて、その値を更新します。

[code]

    override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
        try! realm.write {
            let sourceObject = objects[sourceIndexPath.row]
            let destinationObject = objects[destinationIndexPath.row]
    
            let destinationObjectOrder = destinationObject.order
    
            if sourceIndexPath.row < destinationIndexPath.row {
                // 上から下に移動した場合、間の項目を上にシフト
                for index in sourceIndexPath.row...destinationIndexPath.row {
                    let object = objects[index]
                    object.order -= 1
                }
            } else {
                // 下から上に移動した場合、間の項目を下にシフト
                for index in (destinationIndexPath.row..<sourceIndexPath.row).reverse() {
                    let object = objects[index]
                    object.order += 1
                }
            }
    
            // 移動したセルの並びを移動先に更新
            sourceObject.order = destinationObjectOrder
        }
    }
    
[/code]

しかしRealmには`List`という並び順を保持するデータ型があるので、それを用いたほうが簡単に書けます。

<https://gist.github.com/kishikawakatsumi/543f961f3f70c080218db07850737852>

[code]

    class Data: Object {
        dynamic var name = ""
        ...
    }
    
    class DataWrapper: Object {
        let list = List<Data>()
    }
    
[/code]

上記のように並べ替えたいデータを`List`として保持するクラスを用意します。この方法の良い点としてもう一つ、対象のモデルに手を加える必要がないことも挙げられます。

並べ替えの処理は次のようになります。先ほどのと比べてかなり簡単に書けることがわかります。

[code]

    override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
        try! realm.write {
            let sourceObject = objects[sourceIndexPath.row]
            objects.removeAtIndex(sourceIndexPath.row)
            objects.insert(sourceObject, atIndex: destinationIndexPath.row)
        }
    }
    
[/code]

なお、プライマリキーについてですが、書いてる通り、一度設定したプライマリキーはマイグレーションを除いて変更することはできません。


CC BY-SA 3.0
2017-06-17T04:35:53.930
35657
2017-06-17T04:35:53.930
5519
35653
answer


後者を選ぶとその後特定のKeyからfilterしたりするのが苦労する気がする。  
managed object と unmagaed objectで悩む。  
というかその際の設計がよくわからない。


CC BY-SA 4.0
2019-11-28T15:09:12.910
60927
2019-11-28T15:09:12.910
36837
35653
answer