I have come across this topic in a few searched but still not sure how to make it work. After upgrading from previous RealmSwift SDK to 10.x I now get this " Object already managed…" error. I know it is nested objects or relations causing it but I am not sure how to make it work until this bug is fixed.
Basically, if you are trying to insert or upsert a docuemnt that has a nested objectId it throws this error. Below is some code that I can share that causes the error. I have a user, club, and game model. When creating a new game that has an ObjectId field and an array of ObjectIds, realmSwift requires those model be the model of that particular object itself. For example
class User: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var _partition: String = "partition"
@Persisted var clubId: Club?
@Persisted var fullName: String = ""
...
}
This is a user class that in the database just houses the objectId that related to the club but realmswift requires it to be the club model. this worked fine up until SDK 10.x but now it wont let me write a user to the realm unless i do not include the club nested object. So, this causes many problems as my app revolves around creating new games and has 2-3 nested objects or arrays of objects. Below is some sample of that code that I can share, slightly altered but should give a general idea of what I am dealing with. Any help to work around this until it is fixed is greatly appreciated.
Models:
class User: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var _partition: String = "partition"
@Persisted var clubId: Club?
@Persisted var fullName: String = ""
...
}
Class Club Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var _partition: String = "partition"
@Persisted var clubId: Club?
@Persisted var name: String = ""
...
}
Class Game Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var _partition: String = "partition"
@Persisted var clubId: Club?
@Persisted var hostId: User?
@Persisted var users: RealmSwift.List<User>
...
}
Data:
Game:
{
"_id": { "$oid": "660064c69a7c4bed68509f90" },
"_partition": “partition”,
"clubId": {
"$oid": "5ef944d846779f3aef97c5fb"
},
"hostId": {
"$oid": "6365894c7998127adaa7dde0"
},
“users”: [
{ "$oid": "660169d6c7241ef4e01d9c94" },
{ "$oid": "608e01d21e6d9297988a1838" },
{ "$oid": "6365894c7998127adaa7dde0" }
]
}
User1:
{
"_id": { "$oid": "660169d6c7241ef4e01d9c94" },
"_partition": "partition",
"clubId": {
"$oid": "5ef944d846779f3aef97c5fb"
},
"fullName": "Joe"
}
User2:
{
"_id": { "$oid": "608e01d21e6d9297988a1838" },
"_partition": "partition",
"clubId": {
"$oid": "5ef944d846779f3aef97c5fb"
},
"fullName": "Fred"
}
User3:
{
"_id": { "$oid": "6365894c7998127adaa7dde0" },
"_partition": "partition",
"clubId": {
"$oid": "5ef944d846779f3aef97c5fb"
},
"fullName": "Bob"
}
User4:
{
"_id": { "$oid": "6086f0783b7450f676b81a9d" },
"_partition": "partition",
"clubId": {
"$oid": "5ef944d846779f3aef97c5fb"
},
"fullName": "Tom"
}
Club:
{
"_id": { "$oid": "6601696bc7241ef4e01d9c93" },
"_partition": "partition",
"name": "The Only Club"
}
struct CreateMatch: View {
@EnvironmentObject var state: AppState
@Environment(\.dismiss) var dismiss
@State private var selectedDateTime = Date.now
@State private var isPublic = false
@State private var minRating = 2.5
@State private var maxRating = 7.0
private var newGame = Game()
@Binding private var users: [User]
var gameUsers: RealmSwift.List<User> = RealmSwift.List<User>()
var clearMatchUsers = {}
@State private var showNotFullAlert = false
init(users: Binding<[User]>) {
self._users = users
gameUsers.append(objectsIn: self.users)
UIDatePicker.appearance().minuteInterval = 15
UISegmentedControl.appearance().selectedSegmentTintColor = UIColor(Color.theme.tennisCourtGreen)
}
var body: some View {
ZStack{
ScrollView {
VStack {
... shows some pickers and boxes to change data. View works fine, it's just a problem when writing to realm.
}
}
...
}
}
extension CreateGame {
private func handleLetsPlay() {
createNewGame)
}
private func createNewGame() {
newGame.gameDate = selectedDateTime
newGame.gameDate.users = gameUsers
newGame.gameDate.hostId = state.user
newGame.gameDate.clubId = state.user.clubId
state.writeToRealm(newGame)
}
}
class AppState: ObservableObject {
var loginPublisher = PassthroughSubject<RealmSwift.User, Error>()
var logoutPublisher = PassthroughSubject<Void, Error>()
let userRealmPublisher = PassthroughSubject<Realm, Error>()
var cancellables = Set<AnyCancellable>()
@StateObject var locationManager = LocationDataManager()
@Published var shouldIndicateActivity = false
@Published var isLoggingIn = false
@Published var error: String?
@Published var user: User = User()
@Published var realm: Realm?
var loggedIn: Bool {
app.currentUser != nil && app.currentUser?.state == .loggedIn
}
init() {
logoutPublisher
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in
}, receiveValue: { _ in
self.user = User()
})
.store(in: &cancellables)
}
func openRealm(user: RealmSwift.User) {
let realmConfig = user.configuration(partitionValue: Constants.REALM_PARTITION_VALUE)
let predicate = NSPredicate(format: "userId == %@", app.currentUser?.id ?? "")
Realm.Configuration.defaultConfiguration = realmConfig
Realm.asyncOpen(configuration: realmConfig) { result in
switch result {
case .failure(let error):
self.isLoggingIn = false
self.error = "Failed to open realm: \(error.localizedDescription)"
return
case .success(let realm):
self.realm = realm
if let newUser = realm.objects(User.self).filter(predicate).first {
self.user = newUser
self.isLoggingIn = false
} else {
do {
try realm.write {
let user = User()
user.fullName = ""
user.email = ""
user._partition = Constants.REALM_PARTITION_VALUE
user.userId = app.currentUser?.id ?? ""
realm.add(user, update: .modified)
self.isLoggingIn = false
}
} catch {
self.isLoggingIn = false
self.error = " Could not add user to Realm"
}
}
}
}
}
func writeToRealm(_ object: RealmSwift.Object) {
shouldIndicateActivity = true
if let realm = self.realm {
do {
try realm.write {
realm.add(object, update: .modified)
}
shouldIndicateActivity = false
} catch {
self.isLoggingIn = false
self.error = " Could not add data to Realm"
shouldIndicateActivity = false
}
}
}
}