Komplette CoreData Datenbank auf nil prüfen und korrigieren

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Macoun 2019 - Frühbucherrabatt bis 26.7.2019

  • Komplette CoreData Datenbank auf nil prüfen und korrigieren

    Hallo Freunde der App-Entwicklung,

    ich hatte in einem anderen Forum-Post bereits beschrieben warum ich diese Frage hier stelle und um diese Fragen / Themen nicht zu vermischen hier der neuen Post.

    Das Problem noch einmal kurz zusammen gefasst:

    Durch einen nicht bedachten Fehler kam es dazu, dass nil-Werte in die CoreData-Datenbank geschrieben wurden. Jetzt muss ich die gesamte Datenbank prüfen und alle nil-Werte entfernen.

    Dazu nutze ich nachfolgende Funktion:

    Quellcode

    1. func checkIfCoreDataHasNilValues(){
    2. guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
    3. return
    4. }
    5. let context = appDelegate.persistentContainer.viewContext
    6. let request = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
    7. do{
    8. let results = try context.fetch(request)
    9. if(results.count > 0){
    10. for r in results {
    11. if let result = r as? NSManagedObject{
    12. if( result.value(forKey: "name") as? String == nil){
    13. result.setValue("", forKey: "name")
    14. }
    15. if( result.value(forKey: "mail") as? String == nil){
    16. result.setValue("", forKey: "mail")
    17. }
    18. if( result.value(forKey: "date") as? NSDate == nil){
    19. result.setValue(Date(), forKey: "date")
    20. }
    21. }
    22. }
    23. }else{
    24. print("CHECK User > 0")
    25. }
    26. }catch{
    27. print(error)
    28. }
    29. let request UserData = NSFetchRequest<NSFetchRequestResult>(entityName: "UserData")
    30. do{
    31. let resultsUserData = try context.fetch(requestUserData)
    32. if(resultsUserData.count > 0){
    33. for rUserData in resultsUserData {
    34. if let resultUserData = rUserData as? NSManagedObject{
    35. if( resultUserData.value(forKey: "extradata") as? String == nil){
    36. resultUserData.setValue("no name", forKey: "extradata")
    37. }
    38. }
    39. }
    40. }else{
    41. print("CHECK UserData > 0")
    42. }
    43. }catch{
    44. print(error)
    45. }
    46. ...
    47. weitere Datenbank-Entities
    48. ...
    49. }
    Alles anzeigen
    Meine Frage ist jetzt, ob ihr das genau so machen würdet, oder ob es vielleicht eine, mir noch nicht bekannte, Funktion dafür gibt, um die gesamte Datenbank von nil-Werten zu bereinigen. Da die App bereits von vielen User genutzt wird muss ich echt vorsichtig sein, dass es zu keinem Datenverlusts bei dieser Korrektur kommt.

    Vielen Dank für eure Unterstützung und Tipps! Ich bin gespannt ob ich auf dem richtigen Weg bin, oder ob es auch ganz anders geht! :thumbsup:
    Neu in der IOS-App-Entwicklungswelt - Spannend, ab und an nervenaufreibend, aber am Ende einfach faszinierend. Seid bitte nicht zu streng wenn ich Fragen einmal doppelt stelle, ich lerne noch :saint:
  • Mac & i Test Abo
  • CodeNerd schrieb:

    Meine Frage ist jetzt, ob ihr das genau so machen würdet, oder ob es vielleicht eine, mir noch nicht bekannte, Funktion dafür gibt, um die gesamte Datenbank von nil-Werten zu bereinigen. Da die App bereits von vielen User genutzt wird muss ich echt vorsichtig sein, dass es zu keinem Datenverlusts bei dieser Korrektur kommt.
    Das kommt mir sehr bekannt vor: Ich habe vor kurzem einen ähnlichen Bock geschossen, als ein CoreData-Attribut keinen Initialwert hatte und meine Export-Routine in ein NSDictionary dann bei Verwendung des nil-Wertes abkachelte (Link).

    Eine - vielleicht offensichtliche - Alternative wäre, alle CoreData-nutzenden Methoden so robust zu machen, dass sie mit nicht gefüllten Werten sauber arbeiten. Ich bin nicht sicher, ob das laut Deines anderen Postings nicht schon Dein temporärer Bypass ist...

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von MyMattes ()

  • MCDan schrieb:

    Evtl. lässt sich dies auch über Core Data Model Versioning and Data Migration regeln.
    Hallo MCDan,

    vielen Dank für deine Antwort. Leider verstehe ich die Technik hinter "Core Data Model Versioning and Data Migration" noch nicht komplett und daher habe ich dieses Thema erst einmal nach hinten gestellt, bis ich die Zeit habe, mich damit voll beschäftigen zu können.

    Dennoch vielen Dank für dein Hinweis! Vielleicht ist das Zukünftig eine Möglichkeit :thumbsup:
    Neu in der IOS-App-Entwicklungswelt - Spannend, ab und an nervenaufreibend, aber am Ende einfach faszinierend. Seid bitte nicht zu streng wenn ich Fragen einmal doppelt stelle, ich lerne noch :saint:
  • MyMattes schrieb:

    CodeNerd schrieb:

    Meine Frage ist jetzt, ob ihr das genau so machen würdet, oder ob es vielleicht eine, mir noch nicht bekannte, Funktion dafür gibt, um die gesamte Datenbank von nil-Werten zu bereinigen. Da die App bereits von vielen User genutzt wird muss ich echt vorsichtig sein, dass es zu keinem Datenverlusts bei dieser Korrektur kommt.
    Das kommt mir sehr bekannt vor: Ich habe vor kurzem einen ähnlichen Bock geschossen, als ein CoreData-Attribut keinen Initialwert hatte und meine Export-Routine in ein NSDictionary dann bei Verwendung des nil-Wertes abkachelte (Link).
    Eine - vielleicht offensichtliche - Alternative wäre, alle CoreData-nutzenden Methoden so robust zu machen, dass sie mit nicht gefüllten Werten sauber arbeiten. Ich bin nicht sicher, ob das laut Deines anderen Postings nicht schon Dein temporärer Bypass ist...

    Mattes
    Moin Mattes,

    ja da hattest du ja echt ein ziemlich ähnliches Problem wie ich es derzeit habe. Kann passieren, sollte nicht, aber kann :rolleyes:

    Absolut richtig, die CoreData Methoden habe ich alle angepasst. Dadurch das ich jedes Abfrage eines Properties mit einem Guard gesichert hatte, ist das ganze natürlich nach hinten losgegangen. Das war schlichtweg nicht zu Ende gedacht, da der Problemfall mit nil-Values bis dato unbekannt war. Jetzt ist alles so gesichert:


    Quellcode

    1. Vorher:
    2. guard let name = result.value(forKey: "name") as? String else {
    3. return
    4. }
    5. Nachher:
    6. let name = result.value(forKey: "name") as? String ?? ""
    Läuft :thumbsup:

    Aber zur ursprünglichen Frage zurück, ist dir eine Methode bekannt, die die komplette CoreData-Datenbank "repariert" bzw. von nil-Values befreit?
    Neu in der IOS-App-Entwicklungswelt - Spannend, ab und an nervenaufreibend, aber am Ende einfach faszinierend. Seid bitte nicht zu streng wenn ich Fragen einmal doppelt stelle, ich lerne noch :saint:
  • CodeNerd schrieb:

    Aber zur ursprünglichen Frage zurück, ist dir eine Methode bekannt, die die komplette CoreData-Datenbank "repariert" bzw. von nil-Values befreit?
    Da bin ich bei @MCDan: Wenn Du eine neue Version Deines Datenmodells erzeugst, „vernünftige“ Initial-Werte für die Attribute hinterlegst und per Opt-In eine Data Migration machen lässt, sollte das Problem gelöst sein ... ungetestet, daher Konjunktiv :)

    Mattes

    Edit: Das Thema brauchst Du bei der ersten Anpassung des Datenmodells je und „lightweight migration“ reicht häufig schon...
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • MyMattes schrieb:

    CodeNerd schrieb:

    Aber zur ursprünglichen Frage zurück, ist dir eine Methode bekannt, die die komplette CoreData-Datenbank "repariert" bzw. von nil-Values befreit?
    Da bin ich bei @MCDan: Wenn Du eine neue Version Deines Datenmodells erzeugst, „vernünftige“ Initial-Werte für die Attribute hinterlegst und per Opt-In eine Data Migration machen lässt, sollte das Problem gelöst sein ... ungetestet, daher Konjunktiv :)
    Mattes

    Edit: Das Thema brauchst Du bei der ersten Anpassung des Datenmodells je und „lightweight migration“ reicht häufig schon...

    Ja mit diesem Thema muss ich mich unbedingt noch näher beschäftigen. Bisher hab ich das ganze noch nicht ganz verstanden.

    Also was ich jetzt schon gecheckt habe ist, dass ich keine der Entities editieren (umbenennen, löschen oder hinzufügen von neuen Attributen) und keine Relationen hinzufügen darf ohne diese Migration zu machen, da ansonsten die App crashed. Aber ich darf neue Entities mit Attributen hinzufügen ohne das die App crashed.

    Was mich bisher irritiert hat ist, dass ja eigentlich in Xcode bei der .xcdatamodeld - Datenbank - Datei ein kleiner Pfeil auftauchen soll, der dann die alte und neue Version auswählbar macht. Zumindest habe ich das so in der Tutorials / Videos gesehen. Bei mir kommt das aber nicht. Wenn ich etwas in den Entities ändere, bleibt die .xcdatamodeld eine einfache Datei in Xcode ohne Pfeil? ;(

    Aber das finde ich schon noch raus. Ach ja außerdem soll man ja diese Classes neu erstellen, da das aber Xcode automatisch bisher macht, weiß ich noch nicht genau, ob Xcode das dann bei einer Migration auch automatisch macht. Wisst ihr was ich meine? Mir fehlen hier die Fachbegriffe bei diesem Migrations-Thema sorry! :rolleyes:
    Neu in der IOS-App-Entwicklungswelt - Spannend, ab und an nervenaufreibend, aber am Ende einfach faszinierend. Seid bitte nicht zu streng wenn ich Fragen einmal doppelt stelle, ich lerne noch :saint:
  • CodeNerd schrieb:


    Ach ja außerdem soll man ja diese Classes neu erstellen, da das aber Xcode automatisch bisher macht, weiß ich noch nicht genau, ob Xcode das dann bei einer Migration auch automatisch macht. Wisst ihr was ich meine? Mir fehlen hier die Fachbegriffe bei diesem Migrations-Thema sorry! :rolleyes:
    Du musst zwischen den Core-Data-Classes und dem Datenmodell unterscheiden:
    • Die Classes müssen angepasst werden, damit Du entsprechende Objekte und Properties hast, um auf Entities und Attribute zuzugreifen. Ob Du das (gerade bei Änderungen) selber machst oder Xcode machen lässt, ist für das Datenmodell erst einmal egal.
    • Das Datenmodell (.xcdatamodel) wird in eine .mom-Datei kompiliert und mit der App ausgeliefert. Wenn dieses - z. B. bei einem Update der App - nicht mit der Struktur bestehender Daten übereinstimmt, crasht die App beim Instanzieren des persistentStoreCoordinators.
    Stichworte hast Du oben erhalten ("Core Data Model Versioning and Migration" und "lightweight migration") und @MCDan hat Dir sogar den Link auf Apple's Doku gepostet. dort ist schrittweise genau beschrieben, was Du machen musst, um z. B. eine neue Version des Datenmodels anzulegen.

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • MyMattes schrieb:

    CodeNerd schrieb:

    Ach ja außerdem soll man ja diese Classes neu erstellen, da das aber Xcode automatisch bisher macht, weiß ich noch nicht genau, ob Xcode das dann bei einer Migration auch automatisch macht. Wisst ihr was ich meine? Mir fehlen hier die Fachbegriffe bei diesem Migrations-Thema sorry! :rolleyes:
    Du musst zwischen den Core-Data-Classes und dem Datenmodell unterscheiden:
    • Die Classes müssen angepasst werden, damit Du entsprechende Objekte und Properties hast, um auf Entities und Attribute zuzugreifen. Ob Du das (gerade bei Änderungen) selber machst oder Xcode machen lässt, ist für das Datenmodell erst einmal egal.
    • Das Datenmodell (.xcdatamodel) wird in eine .mom-Datei kompiliert und mit der App ausgeliefert. Wenn dieses - z. B. bei einem Update der App - nicht mit der Struktur bestehender Daten übereinstimmt, crasht die App beim Instanzieren des persistentStoreCoordinators.
    Stichworte hast Du oben erhalten ("Core Data Model Versioning and Migration" und "lightweight migration") und @MCDan hat Dir sogar den Link auf Apple's Doku gepostet. dort ist schrittweise genau beschrieben, was Du machen musst, um z. B. eine neue Version des Datenmodels anzulegen.

    Mattes
    OK, ich danke dir für die detaillierte Erklärung der Unterschiede. Jetzt habe ich das endlich verstanden. :D

    Das Thema Migration schaue ich mir noch einmal ganz genau an. Bis dahin belasse ich es erst einmal bei meiner manuellen Überprüfung.

    @MCDan @MyMattes Ich danke euch :thumbsup:
    Neu in der IOS-App-Entwicklungswelt - Spannend, ab und an nervenaufreibend, aber am Ende einfach faszinierend. Seid bitte nicht zu streng wenn ich Fragen einmal doppelt stelle, ich lerne noch :saint: