Reputation: 1441
I am building a Swift iOS app using Swift 2.1.1
and RealmSwift 0.97.1
. My initial requirements involved a one-to-one relation between classes A
and B
so I wrote the following:
class A: Object {
dynamic var b: B? // A has one B
}
class B: Object {
var a: A {
return linkingObjects(A.self, forProperty: "b")[0]
}
}
This worked well but now my requirements have changed and I need a one-to-many relation:
class A: Object {
var bs: [B] {
return linkingObjects(B.self, forProperty: "a")
}
}
class B: Object {
dynamic var a: A? // B belongs to A
}
I have users with real data so I would really like to push out this change gracefully using migrations.
From what I have tried, it's not possible to change a relation from within a migration (I get Can not add objects from a different Realm
). Is this actually the case?
As a workaround, I create a dictionary that maps A primary keys to B primary keys. This also means I had to add a primary key to B which didn't previously have one. Then, outside the migration, I change the order of the relation:
for (aKey, bKey) in keyMap {
let a = realm.objectForPrimaryKey(A.self, key: aKey)
let b = realm.objectForPrimaryKey(B.self, key: bKey)
b?.a = a
a?.b = nil
}
This works but I can't seem to get rid of A
's b
property. If I try to remove it, the part of the migration that builds the dictionary fails: there is no link between A
s and B
s if I use newObject
and there is no primary key for B
if I use oldObject
. This all would work fine if I could sequence the updates (first add the primary key, then build the dictionary, then delete the b
property) but I don't think that's possible.
Is there a better way to approach making this change? If not, is there a way I can remove the b
property?
Upvotes: 1
Views: 1590
Reputation: 8138
If all of your B
objects are linked to by exactly one A
object, you can do the following in your migration:
migration.deleteData("B")
migration.enumerate("A") { oldObject, newObject in
let b = migration.create("B", value: oldObject!["b"]!)
(newObject!["bs"] as! List<MigrationObject>).append(b)
}
This works around the fact that you can't get a reference to the linked object which is compatible with newObject
without keeping the property b
by instead deleting all of the existing B
objects and instead linking to new copies of them.
Upvotes: 2