2015-11-04 11 views
9

Ich habe viele Fragen bezüglich Stapellöschung in Core Data gesehen, aber keine scheint mein Problem anzugehen.Core Data NSBatchDeleteRequest scheint Objekte im Kontext zu belassen

Ich erstelle eine iOS 9/Swift App mit Core Data. Auf der WWDC dieses Jahr besuchte ich die Core Data Session und sah, dass ich NSBatchDeleteRequest verwenden konnte, um eine große Anzahl von Objekten direkt aus dem persistenten Speicher zu löschen. Das funktioniert für mich bei einigen Objekten, aber nicht bei anderen, und ich denke, es hat etwas mit meinen Beziehungen zu tun.

Ich habe ein Objekt-Graph bestehend aus Subject und Course, wo es eine Eins-zu-viele-Beziehung gibt. Die Teilnehmer können so viele Kurse besitzen, wie sie möchten.

Es gibt eine Beziehung ‚Kurse‘ auf Subject mit einer Löschregel Cascade, wie ich möchte, dass alle mit einem subject zugehörigen Kurse gelöscht werden, wenn ein subject gelöscht.

Die Umkehrung ist 'Betreff' auf Course, mit einer Löschregel von Nullify. Hier bin ich ein wenig verwirrt als Apples Beschreibung von Nullify:

Entfernen Sie die Beziehung zwischen den Objekten, aber löschen Sie keines der Objekte. Dies ist nur sinnvoll, wenn die Abteilungsbeziehung für einen Mitarbeiter optional ist oder wenn Sie vor dem nächsten Sicherungsvorgang für jeden Mitarbeiter eine neue Abteilung festlegen.

Das macht es ziemlich klar, aber warum sollten die Beziehungen gelöscht werden, aber nicht irgendein Objekt? Wenn ich ein Course löschen, mag ich die Course vom subject zum course gelöscht und die Beziehung werden, um gelöscht werden, so dass ein Fehler auf die gelöschte Course nicht in den NSSet auf Subject ‚s courses Sets erscheinen.

Ich möchte einen Weg für alle Objekte in einer Entität bereitstellen, die gelöscht werden sollen. Wenn ich dies einzeln durchholen und löschen möchte, werden alle course, courses ordnungsgemäß gelöscht und aus der NSSetcourses auf eine Subject entfernt.

Da ich keine Ahnung habe, wie viele courses wird anwesend sein und ich möchte eine hohe Leistung in jeder Situation zu gewährleisten, dachte ich, ich würde Batch löschen verwenden, um alle courses zu löschen. Das Problem ist, dass bei der Verwendung NSBatchDeleteRequest zu löschen alle Subjects funktioniert gut, Löschen aller courses auf dem Weg (wegen der Cascade Regel), versucht, alle Courses mit dieser Methode zu löschen scheint alle Objekte an Ort und Stelle zu lassen.

benutzen ich NSBatchDeleteRequest alle Courses, zu löschen, aber dann, wenn ich die MOC abfragen, um zu sehen, was Subjects und Courses noch existieren, beide Courses noch zurückgegeben werden und die Subject sie hat immer noch Verweise auf sie zu besitzen.

Im Gegensatz dazu, wenn ich jeden Course einzeln abrufen und löschen, meine nachfolgende holen richtig zeigt ein leeres Array für alle Courses und die Beziehung auf der Subject ‚Kurse‘ erscheint richtig verändert wurden.

Ja, ich speichere den Kontext nach der Ausführung der Anfrage. Ich nehme an, der Kontext kann nicht benachrichtigt werden, was der Laden tut, aber dann wieder löschte alle subjects funktioniert großartig. Was geht hier vor sich?

+0

Batch löscht ignorieren löschen Regeln. https://stackoverflow.com/questions/32915874/cani-i-use-nsbatchdeleterequest-on-entities-with-relationshat-have-delete-r/46073965#46073965 – LShi

Antwort

24

Bei the WWDC 2015 session which describes NSBatchDeleteRequest wurde erläutert, dass "Änderungen nicht im Kontext widerspiegeln". Was du siehst, ist normal. Batch-Aktualisierungen arbeiten direkt in der Datei für den persistenten Speicher, anstatt den Kontext des verwalteten Objekts durchzugehen, sodass der Kontext nichts über sie weiß. Wenn Sie die Objekte durch Abrufen und dann Löschen löschen, arbeiten Sie den Kontext durch, damit er über die Änderungen informiert wird, die Sie vornehmen (in Wirklichkeit führt er diese Änderungen für Sie durch).

Wenn Sie NSBatchDeleteResultTypeObjectIDs verwenden, können Sie die Ergebnisse der Stapellöschung wieder in Ihren Kontext einfügen, indem Sie mergeChangesFromRemoteContextSave:intoContexts: verwenden, um Ihre Kontexte zu aktualisieren. Sie könnten wahrscheinlich auch reset verwenden, wenn Sie keine anderen verwalteten Objekte aus dem Kontext geladen haben.

+0

Danke! Ich habe zurückgesetzt und es hat funktioniert. Bevor ich Ihre Antwort sah, sah ich, dass Kurse in der SQLite-Datenbank fehlten und die App dies beim Relaunch widerspiegelte. –

+0

Ich möchte auf die mergeChanges-Methode für die Sicherheit wechseln. Ich habe eine Kopie des Stapellöschungsergebnisses, das ich als "NSBatchDeleteResultTypeObjectID" zurückgeben möchte. Was übermittele ich für 'changeNotificationData: [NSObject: AnyObject]' auf 'mergeChangesFromRemoteContextSave'? –

+0

Okay, anstatt 'NSBatchDeleteResultTypeObjectID' zu verwenden, habe ich mich für den' NSManagedObjectContextDidSaveNotification' registriert und 'mergeChangesFromRemoteContextSave' aus dem Block aufgerufen. –

2

Ich fügte hinzu, das folgende, um den Kontext nach dem Batch löschen zu kümmern.

[self.managedObjectContext refreshAllObjects];