I have next code to update my workout:
func addMuscleGroups(muscleGroups: [MusclEntity], toWorkout: WorkoutEntity, completion: @escaping (ResultInfo<WorkoutEntity>) -> Void) {
CoreStore.perform(
asynchronous: { (transaction) -> WorkoutEntity? in
let workout = transaction.edit(toWorkout)!
for muscle in muscleGroups {
let editedMuscle = transaction.edit(muscle)!
workout.muscles?.insert(editedMuscle)
}
return workout
},
success: { (transactionWorkout) in // here we have muscles for transactionWorkout
guard let unwrappedTransactionWorkout = transactionWorkout else {
return
}
let workout = CoreStore.fetchExisting(unwrappedTransactionWorkout) // there are no muscles objects
guard let unwrappedWorkout = workout else {
return
}
completion(.data(unwrappedWorkout))
},
failure: { (error) in
completion(.error(StackedError.internalFetchingDataError(message: error.debugDescription)))
})
}
But as I see I have inserted muscles while perform asynchronous block, but then when I do fetchExisting there are no muscles which were added in asynchronous block.
EDITED:
As I figured out there is missing relationships inverse in workout.muscles, now I added it and looks like CoreStore update workout entity correctly.
But now I have another problem if I call function few times:
addMuscleGroups([1, 2, 3, 4, 5]...) print(unwrappedWorkout.muscles) [1, 2, 3, 4, 5]
second call addMuscleGroups([1, 2, 3, 4, 5, 6, 7]...)
print(unwrappedWorkout.muscles) [6, 7]
(to simplify example I used 1, 2, 3, 4, 5, 6, 7 numbers), but there are MusclEntity objects actually
so as a result of second call of addMuscleGroups function unwrappedWorkout.muscles has two muscle objects instead of 7.
I've added short video:
I answered your question at CoreStore's github as well.
This would be the general behavior of NSManagedObject
s with regards to to-many properties.
First, as you have found out, the inverse relationship is important.
Second, Set
is not recommended for unordered @NSManaged
properties. Using NSSet
is recommended instead.
In that note, to-many relationships are treated as immutable, which means you cannot insert objects directly to the NSSet
value. There are two ways you can insert values.
NSSet
directly:var muscles = (workout.muscles as! Set<MusclEntity>?) ?? []
muscles.insert(newMuscle)
workout.muscles = muscles as NSSet
NSMutableSet
proxy for you):workout.mutableSetValueForKey(#keyPath(WorkoutEntity.muscles))
.addObject(newMuscle)