I have the problem in my app, that deleting a lot of data out of my Database takes very long. So I started debugging and found out, that the value-transformers are the problem!
To see the problem I created a project that isolates the problem...
I have the following:
+-----------+ +-----------+
| Entity A | | Entity B |
+-----------+ +-----------+
| | | property |
| b | 1:1 | a |
+-----------+ +-----------+
So Entity A
has a 1:1 relation to Entity B
. And Entitiy B
has a property called property
which is Transformable and has a ValueTransformer. The delete rule of A to B is nullify.
Now I create one instance of A and B, link them and write something into property. Save the context and everything works as expected.
Now I want to delete all object of Entity A
. I create a fetch request, and delete all entities. In my sample I do that like so:
context.perform {
let fetchRequest = NSFetchRequest<EntityA>(entityName: "EntityA")
guard let allEntities = try? context.fetch(fetchRequest) else { return }
for entity in allEntities {
context.delete(entity)
}
try? context.save()
}
And now when that save happens, the value transformers reverseTransformedValue
is called. And I don't understand WHY?!? Cause I don't access that property... I don't set or get it...
Would be cool if somebody could shed some light for me.
I also have my sample project available here: https://www.dropbox.com/s/651dmyughosr90p/ValueTransformerIssue-Sample.zip?dl=0
This is an interesting and somewhat surprising result, but I think it's Core Data operating normally. A couple of background details on Core Data:
In your case what appears to be happening is:
EntityA
.EntityA
means that Core Data needs to modify the corresponding EntityB
by setting its value for a
to nil.EntityB
instance. Since it's modifying one of the properties, it first loads all of the properties. At this point your value transformer executes even though it isn't really needed here.If your value transformers are hurting performance, some things you might try to fix that include:
EntityB
. Relationships faults don't fire when property faults do, so the nullify rule wouldn't load instances of this new entity.NSBatchDeleteRequest
will not honor delete rules (so "nullify" won't be applied), you might be able to combine one with an NSBatchUpdateRequest
to fix the relationship. Something like, do a batch delete for EntityA
instances followed by a batch update to set the relationship to nil on affected EntityB
instances.Or of course, maybe your value transformer can be optimized so that it's less of a problem?
Hope this helps. Good luck!