Mulgard
Mulgard

Reputation: 10609

Realm Migration: Move an Object from one Object to another Object

I have three objects:

class Customer: Object {
    dynamic var solution: Solution!;
    ...
}

class Solution: Object {
    dynamic var data: Data!;
    ...
}

class Data: Object {
    ...
}

Now i need to move the Data Object from Solution to Customer so that it becomes:

class Customer: Object {
    dynamic var solution: Solution!;
    dynamic var data: Data!;
    ...
}

I have no idea how I have to implement my Realm Migration method so that everything works fine and that I wont lose data.

Upvotes: 0

Views: 2294

Answers (2)

Eli Burke
Eli Burke

Reputation: 2789

Swift 4, Realm 3

I had to migrate a Realm object that linked to another object. I wanted to remove the explicit link and replace it with an object ID. TiM's solution got me most of the way there, and just needed a little refinement.

   var config = Realm.Configuration()
   config.migrationBlock = { migration, oldSchemaVersion in
        if oldSchemaVersion < CURRENT_SCHEMA_VERSION {

            // enumerate the first object type
            migration.enumerateObjects(ofType: Message.className()) { (oldMsg, newMsg) in 

                // extract the linked object and cast from Any to DynamicObject
                if let msgAcct = oldMsg?["account"] as? DynamicObject {

                    // enumerate the 2nd object type
                    migration.enumerateObjects(ofType: Account.className()) { (oldAcct, newAcct) in
                        if let oldAcct = oldAcct {

                             // compare the extracted object to the enumerated object
                             if msgAcct.isEqual(oldAcct) {

                                // success!
                                newMsg?["accountId"] = oldAcct["accountId"]
                            }
                        }
                    }
                }
            }
        }

Upvotes: 1

TiM
TiM

Reputation: 16021

I did some experiments with the Realm migrations sample app and came up with this potential solution:

In a migration block, you can only interact with your Realm file via the migration object. Any attempts to directly access the Realm file mid-migration will result in an exception.

That being said, it's possible to have nested calls to migration.enumerateObjects referencing different Realm model object classes. As such, it should simply be a matter of initially enumerating through the Customer objects, and in each iteration, enumerate through the Solution objects to find the corresponding one with the right data value. Once found, it should be possible to set the Customer object with the data from the Solution object.

Realm.Configuration.defaultConfiguration = Realm.Configuration(
    schemaVersion: 1,
    migrationBlock: { migration, oldSchemaVersion in
        if (oldSchemaVersion < 1) {
            migration.enumerateObjects(ofType: Customer.className()) { oldCustomerObject, newCustomerObject in
                migration.enumerateObjects(ofType: Solution.className()) { oldSolutionObject, newSolutionObject in
                    //Check that the solution object is the one referenced by the customer
                    guard oldCustomerObject["solution"].isEqual(oldSolutionObject) else { return }
                    //Copy the data
                    newCustomerObject["data"] = oldSolutionObject["data"]
                }
            }
        }
    }
})

I feel I need to stress that this code is by no means tested and guaranteed to work in its present state. So I recommend you make sure you thoroughly test it on some dummy data you wouldn't miss beforehand. :)

Upvotes: 2

Related Questions