[Résolu] CoreData : Max 100 attributes

2»

Réponses

  • Merci AliGator pour tout ça.


    L'histoire est que dans mon projet, on navigue entre les écrans dans tous les sens.


    C'est à  dire que l'on peut aller :


    - A l'écran suivant


    - A l'écran précédent


    - A n'importe quel écran - En accès direct, quoi.


     


    1- Et, en quittant un écran pour un autre, il faut évidemment que ses variables soient stockées dans le coredata.


    Je ne les stocke d'ailleurs pas en quittant l'écran, mais à  chaque manip sur l'écran.


     


    2- Je dois donc, à  chaque écran, connaà®tre au moins le nom du patient (qui est dans la première entité) - ça, j'y arrive bien avec le predicate.... Puis stocker les variables de l'écran en question en (1-) dans une entité appropriée, reliée (relationship) évidemment à  la première entité.


     


    3- Je ne peux donc pas attendre que le formulaire (selon ton exemple) soit rempli complètement pour le sauver dans coredata, mais sauver chacun des feuillets (une quarantaine) pratiquement en temps réel pour chaque ligne remplie.


    C'est ce que je fais actuellement. ça marche nickel, mais avec une seule entité de 300 attributs


    Je suis en train de créer mes autres entités en relationship.


     


    J'ai fait un essai sur une variable (une ligne d'un feuillet du formulaire) dans un écran. C'est ok.


    Je suis par contre convaincu de ne pas avoir la bonne méthode selon MVC.


     


    Je me suis refait plein de cours là -dessus (la sorbonne - Ray Wenderlish - Apple


     


    Je me rend compte que la grosse partie traitement des infos est dans mes controllers, et donc je ne suis pas trop MVC.


     


    J'ai un gros problème pour avancer, et c'est justement lié au MVC, j'en suis certain.


     


     


     


     


    Prenons l'exemple de ton formulaire, avec 40 feuillets de 20 lignes chacun.


    Au premier feuillet, on enregistre, Nom, prénom, etc... dans la première entité - Patients par exemple d;-)


     


    Puis, si je vais ensuite ET directement sur le feuillet 27.


     


     


    Problème 1 :


     


    Puisqu'il est vide la première fois que j'y vais, je ne peux donc pas récupérer ses lignes remplies au cas où elles l'ont été (pour les afficher), avant d'éventuellemnt les remplir ou les modifier., en faisant cela :


    (J'ai mis des noms bidons pour que ce soit explicite)



    let UnPatient: Patients = fetchResults.lastObject as! Patients
    let UnFeuillet27 = UnPatient.feuillet27

    J'ai fait l'essai, lorsque j'enregistre mon premier feuillet, de mettre tous les attributs du feuillet 27 à  "" :



    var newPatient: Patients! = nil
    var newFeuillet27: Feuillet27! = nil

    @IBAction func saveButton(sender: AnyObject) {
    var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    var context: NSManagedObjectContext = appDel.managedObjectContext!
    let entityDescriptionPatient = NSEntityDescription.entityForName("Patients", inManagedObjectContext: context)

    newPatient = Patients(entity: entityDescriptionPatient!, insertIntoManagedObjectContext: context) as Patients
    newPatient.nom = nomTextField.text
    newPatient.prenom = prenomTextField.text
    newPatient.sexe = sexeTextField.text


    let entityDescriptionFeuillet27 = NSEntityDescription.entityForName("Feuillet27", inManagedObjectContext: context)
    newFeuillet27 = Feuillet27(entity: entityDescriptionFeuillet27!, insertIntoManagedObjectContext: context) as Feuillet27

    newFeuillet27.ligne1 = ""
    newFeuillet27.ligne2 = ""
    newFeuillet27.ligne3 = ""
    newFeuillet27.ligne4 = ""
    newFeuillet27.ligne5 = ""

    newPatient.Feuillet27 = newFeuillet27

    context.save(nil)

    self.navigationController?.popViewControllerAnimated(true)
    }

    ça marche nickel. Mais je sais que c'est débile : je ne vais quand même pas mettre les 20 lignes des 40 feuillets à  ""; lors de l'enregistrement du premier patient.


     


     


    Problème 2 :


    Pour l'instant sur le feuillet 27, (avec les lignes à  ""), j'essaie de stocker dans un dictionnary, ainsi : et ça marche.



    var UnFeuillet27: Feuillet27! = nil
    var feuillet27Dict = [String : String]()


    let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context: NSManagedObjectContext = appDel.managedObjectContext!
    let entityDescription = NSEntityDescription.entityForName("Patients", inManagedObjectContext: context)

    let fetchRequest: NSFetchRequest = NSFetchRequest()
    fetchRequest.entity = entityDescription
    fetchRequest.returnsObjectsAsFaults = false
    let predicate: NSPredicate = NSPredicate(format: "nom == '\(listeDesVariables.nomString)'")
    fetchRequest.predicate = predicate
    let fetchResults: NSArray = context.executeFetchRequest(fetchRequest, error: nil)!

    let UnPatient: Patients = fetchResults.lastObject as! Patients

    UnFeuillet27 = UnPatient.feuillet27

    feuillet27Dict["ligne1"] = UnFeuillet27.ligne1

    Puis je l'affiche ainsi :



    labelLigne1.text = etape2Dict["e2L1LigneSourire"]

    Je stocke d'abord dans le dictionnary, pour le récupérer plus loin, car je suis (dans mon projet) dans des pageViews, autrement dit pour le fameux formulaire, j'ai en plus, pour faciliter les choses, des groupes de feuillets plutôt que des feuillets individuels.


     


    Donc, je sais que je me démerde mal. J'ai l'impression d'être justement confronté au pattern MVC que je ne respecte pas.


     


    Je devrais avoir certainement une classe à  part qui gère ces variables en tableau ou dictionnary, certainement une par feuillet, puis sur les controllers de chaque feuillets, récupérer les lignes - MVC, quoi !!!


     


    Et donc je suis perdu.


     


     


     


     


    En résumé 2 questions :


    MVC pour les données de chaque feuillet - Faut faire des classes en plus, avec des fonctions dedans... ?


    Et les lignes vides des feuillets non remplis = "" au départ du premier feuillet - Hummm, pas bon


     


     


    Merci d'avance

  • Colas2, désolé, mais j'entrave quedalle.


     


    Magiic



     


     


    Patients est écris en dur or pour ma part je l'écrirais comme une constante puisque tu risques de l'utiliser de nombreuses fois. ça évite des erreurs et si demain tu veux modifier le nom de ton entité pour X raisons, tu ne le fais qu'à  un seul endroit.

    Ok, logique, je n'avais pas penser à  le faire pour ce cas.


  • colas_colas_ Membre
    septembre 2015 modifié #34

    Tu peux avec core data assigner une valeur par défaut. Directement dans l'éditeur de modèle. Tu pourrais mettre tous tes "" là . (Mais je pense que ce problème est secondaire. En vrai, tu es confronté à  un problème d'archi)


     


    Mon message n'était pas très clair, désolé (le fait de l'écrire depuis l'iPad n'aidant pas).


  • AliGatorAliGator Membre, Modérateur

    3- Je ne peux donc pas attendre que le formulaire (selon ton exemple) soit rempli complètement pour le sauver dans coredata, mais sauver chacun des feuillets (une quarantaine) pratiquement en temps réel pour chaque ligne remplie.
    C'est ce que je fais actuellement. ça marche nickel, mais avec une seule entité de 300 attributs
    Je suis en train de créer mes autres entités en relationship.

    Tu peux toujours faire des save intermédiaires, et tu auras donc des entités Patients (+ leurs objets liés) qui ne seront remplis que partiellement
     
     

    ça marche nickel. Mais je sais que c'est débile : je ne vais quand même pas mettre les 20 lignes des 40 feuillets à  ""; lors de l'enregistrement du premier patient.

    Pourquoi ne pas marquer ces attributs comme optionels dans ton modèle CoreData (et du coup les laisser à  nil par défaut tant que tu ne les remplis pas) ?
  • CéroceCéroce Membre, Modérateur

    Je t'avoue que j'ai un peu survolé le sujet, mais pose-toi la question: comment ferais-tu si tu n'avais pas Core Data ?


    ça te paraà®trait logique d'avoir une seule classe avec toutes les propriétés dedans ?


    Bien sûr que non, tu aurais un objet Cabinet, qui comporterait des objets de la classe Patient, qui comporterait lui-même d'autres objets.


     


    Eh, bien figure-toi qu'avec Core Data, c'est pareil. L'idée de Core Data est quand même de faire correspondre une classe (sous-classe de NSManagedObject) à  une Entité.


     


    Ensuite, tes problèmes d'écrans, ça ne nous parle pas trop, parce que de notre point de vue c'est assez direct, en fait: le contrôleur fait la synchro entre les vues et les NSManagedObject.


     


    Après, le fait que tu aies mis les traitements dans les contrôleurs, c'est une mauvaise idée parce que:


    1) le principe crée plein de duplication de code.


    2) ça alourdit les contrôleurs qui sont déjà  assez complexes comme ça.


    3) les contrôleurs sont difficiles à  tester en tests unitaires


     


    Alors, oui, il faut que tu remettes les choses à  plat, à  commencer par ton modèle. Ensuite, ça ira beaucoup mieux.


  • Céroce.



     


    Je t'avoue que j'ai un peu survolé le sujet, mais pose-toi la question: comment ferais-tu si tu n'avais pas Core Data ?


    ça te paraà®trait logique d'avoir une seule classe avec toutes les propriétés dedans ?



    Ben je suis développeur web, et les bdds sont gérées avec phpMyadmin, et là , tu n'as qu'une seule base avec plusieurs tables, effectivement, mais le nombre de champs de chacune des tables n'est pas limité (enfin, il me semble, je ne suis pas un superPro...)


     


    Mais en écrivant, je crois que je comprend ce que tu veux dire. Une table = une entité.


     



     


     


    Après, le fait que tu aies mis les traitements dans les contrôleurs, c'est une mauvaise idée parce que:

    Ben oui, je sais, je l'ai dit, c'est débile.


     


     


     


    Colas2



     


     


    Tu peux avec core data assigner une valeur par défaut. Directement dans l'éditeur de modèle. Tu pourrais mettre tous tes "" là 

    Justement j'avais cherché et pas trouvé. Et là , je viens de voir le champ approprié mais j'y met quoi ?


    "" ou espace ? espace je pense...


     


    Mais ça, c'est une bonne nouvelle. J'achète.


     


    AliGator



     


     


    Pourquoi ne pas marquer ces attributs comme optionels dans ton modèle CoreData (et du coup les laisser à  nil par défaut tant que tu ne les remplis pas) ?

    Ben justement, ils le sont - La petite boite est cochée.


     


    Et en plus, (dans le cas où je ne met pas à  ""), quand je fais le test 




    let UnPatient: Patients = fetchResults.lastObject as! Patients

    if UnPatient.feuillet27 != nil {
    ...
    }

    ça tombe en erreur - Genre (je ne me souviens pas trop, mais...) : UnPatient.feuillet27 (ou Feuillet27) ne peut pas être comparé à  nil


  • Je pense qu'il faudrait que tu arrêtes tout un moment.


     


    Pose à  plat ta grande table avec tes 100+ attributs. Lâche ton Mac, ne code pas, ne te préoccupes par pour l'instant des soucis de code.


     


    Fais des regroupements " logiques ". Trouve de " mini-modèles " (comme une photo, un offset, un zoom, etc.) qui sont répétés, et peuvent-être réutilisés.


     


    Nomme tes nouvelles entités de manière logique et en en fonction de leur sens, pas en fonction de leur ordre d'apparition. Si demain, on te dit de changer l'ordre des écrans, ça s'ra galère pour s'y retrouver.


     


    Reviens sur ton Mac, et commence à  coder, petit à  petit. Dès que tu as un soucis, essaye de l'analyser, car c'est ce qui semble te manquer par fois, un minimum d'analyse, ce qui inclut un minimum de recul. Ne fonce pas tête baissée.


  • CéroceCéroce Membre, Modérateur
    septembre 2015 modifié #39


    Céroce.


    Ben je suis développeur web, et les bdds sont gérées avec phpMyadmin, et là , tu n'as qu'une seule base avec plusieurs tables, effectivement, mais le nombre de champs de chacune des tables n'est pas limité (enfin, il me semble, je ne suis pas un superPro...)


     


    Mais en écrivant, je crois que je comprend ce que tu veux dire. Une table = une entité.




    Comprends bien que ce n'est pas une limitation technique: mais un warning qui explique que tu es en train de faire une connerie.


     


    Evidemment, dans une base SQLite, on peut tout à  fait créer des  tables avec un grand nombre de colonnes. Déjà , ça te fait tiquer, mais c'est ce que tu fais: une seule table avec plein de colonnes, mais une seule ligne ! Est-ce que ça fonctionnerait ? Oui.


     


    Après, dire qu'une table = une entité est à  moitié vrai. Mais ça veut quand même dire que tu commences à  comprendre.


     


    C'est à  moitié vrai parce que Core Data n'utilise pas forcément une base SQLite comme stockage.


    L'autre raison, c'est que tu n'as pas en Core Data de tables relationnelles. Dans une BdD relationnelle, tu as des tables qui ne servent qu'à  associer. Par exemple une table CabinetPatient pour faire correspondre les id des cabinets et les id des patients. Si tu ouvres ton fichier Core Data avec un éditeur de base SQLite, tu verras que de telles tables sont bien présentes, mais dans le schéma Core Data: l'entité Cabinet a une relation to-many vers l'entité Patient. Tu te moques de comment c'est stocké en interne.


     


    Même si Apple s'en défend, Core Data est ce qu'on appelle une ORM (Object-Relationship Mapping). Le but est que le programmeur ne voie que des objets, sans savoir s'il y a une BdD derrière ou pas. Donc, il faut que tu penses "objet", pas BdD. Un changement de culture est toujours difficile, donc tu es tout excusé.


  • AliGatorAliGator Membre, Modérateur

    Ben je suis développeur web, et les bdds sont gérées avec phpMyadmin, et là , tu n'as qu'une seule base avec plusieurs tables, effectivement, mais le nombre de champs de chacune des tables n'est pas limité (enfin, il me semble, je ne suis pas un superPro...)

    Alors peut-être que MySQL te permet de faire une table qui a 300 colonnes. Mais c'est pas parce que c'est possible techniquement que c'est une bonne chose. D'ailleurs en pratique j'espère que même pour le Web tu ne fais pas des tables à  300 colonnes !! Sinon bonjour la performance d'un SELECT (sans parler de l'orga de la base et son optimisation, ni même de sa flexibilité), et ça veut aussi dire que tu as sans doute mal découpé ton problème côté Web également. La problématique de "mauvaise approche d'avoir une seule entité/table contenant 300 attributs/colonnes" est la même, au niveau archi de ton app c'est pas une bonne chose.

    Mais en écrivant, je crois que je comprend ce que tu veux dire. Une table = une entité.

    Oui, effectivement, conceptuellement, une entité CoreData = une table de MySQL, c'est quasiment le même concept (enfin pour simplifier, après y'a des petites subtilités quand tu as des relationships vers plus d'un élément ("*<->*") mais bon)
  • busterTheobusterTheo Membre
    septembre 2015 modifié #41

    Céroce



     


     


    Donc, il faut que tu penses "objet", pas BdD

    Ouais, here is the problem



     


     


    donc tu es tout excusé

    hummm, c'est bon ça...  :p


     


    Larme



     


     


    Je pense qu'il faudrait que tu arrêtes tout un moment.

    Tu as raison, c'est ce que je fais, enfin, c'est pas vrai, mais je temporise et prend des cours, bien qu'il soit un peu tard, car je devais livrer aujourd'hui. Lorsqu'on m'a proposé ce projet, j'avais le choix d'accepter ou de refuser. Le plaisir de m'y remettre et le besoin de rentrées financières ne m'ont pas fait hésiter. Je savais que je me lançais dans une sacrée aventure. Et là , je suis au fait même de l'histoire. C'est la vraie vie, ça. Que veut-tu.


     



     


     


    Nomme tes nouvelles entités de manière logique et en en fonction de leur sens, pas en fonction de leur ordre d'apparition. Si demain, on te dit de changer l'ordre des écrans, ça s'ra galère pour s'y retrouver.

    Là , t'as grave raison. Mais j'ai bloqué l'histoire dès le début. L'ordre est fixé une bonne fois pour toute. Mais sur une V2 ou uneV3, je serais baisé. Et donc, comme le disait, je ne sais plus qui, mais ce sont la plupart des intervenant sur ce post, je dois et devrais faire ainsi. Je peux encore le faire, puisque j'en suis à  reconstruire la totalité de mon coredata. Merci à  toi et aux autres pour cette insistance sur ce sujet. Là , je suis enfin super convaincu. C'est con, puisque toutes mes variables dans tous mes controllers sont nommées ainsi e2L2; e2L3, e3L1, et3L2, etc. Pfff. J'ai fait que d'la merde :D



     


     


    Ne fonce pas tête baissée

    T'inquiète... Merci pour ton empathie. 


     


    Grâce à  colas2, j'ai pu résoudre le problème des entité reliées à  nil ou pas à  nil avec ça (le ? sur la relation). C'était tout con, mais faut avoir le niveau, que je n'ai pas encore :



    import Foundation
    import CoreData


    @objc(Patients)
    class Patients: NSManagedObject {
    @NSManaged var nom: String
    @NSManaged var prenom: String
    @NSManaged var sexe: String
    @NSManaged var etape1: Etape1?
    }

    Ainsi je peux faire ça (avec le !), même si on n'est pas allé sur l'écran en question :



    if singlePatient.etape1 != nil {
    let etape1 = singlePatient.etape1
    poignee1Fiche.text = etape1!.poignee1
    poignee2Fiche.text = etape1!.poignee2
    poignee3Fiche.text = etape1!.poignee3
    poignee4Fiche.text = etape1!.poignee4
    poignee5Fiche.text = etape1!.poignee5
    }

    Encore merci à  vous tous, et aussi à  colas2 qui vient de passer plus d'une heure sur le chat avec moi. Ce fut laborieux pour lui, car je n'ai pas tout le jargon et l'expérience POO appropriée.


     


    Je propose de mettre résolu.


     


    Je vais créer un nouveau post pour une énorme question concernant l'upload d'une appli par un utilisateur tout en conservant ses données coredata. A la votre :p .


  • Plus besoin d'ajouter les ? à  la main dans les classes modèle.


     


    Update for Xcode 7: This issue has been solved with Xcode 7 beta 2. Optional Core Data properties are now defined as optional properties in the managed object subclasses generated by Xcode. It is no longer necessary to edit the generated class definition.


     


    http://stackoverflow.com/a/25664102/1670830


  • pfff - ils sont très lourds


  • enfin, merci - t'assures.


  • AliGatorAliGator Membre, Modérateur
    septembre 2015 modifié #45

    Ainsi je peux faire ça (avec le !), même si on n'est pas allé sur l'écran en question :

     if singlePatient.etape1 != nil {
    let etape1 = singlePatient.etape1
    poignee1Fiche.text = etape1!.poignee1
    poignee2Fiche.text = etape1!.poignee2
    poignee3Fiche.text = etape1!.poignee3
    poignee4Fiche.text = etape1!.poignee4
    poignee5Fiche.text = etape1!.poignee5
    }

    Bon bah maintenant tu n'as plus qu'à  aller lire mon article de blog "Thinking in Swift: Saving ponies" que j'ai déjà  mentionné plus haut, histoire de sauver des poneys en évitant d'utiliser ces "etape1!" partout ;-)


    if let etape1 = singlePatient.etape1 {
    poignee1Fiche.text = etape1.poignee1
    poignee2Fiche.text = etape1.poignee2
    poignee3Fiche.text = etape1.poignee3
    poignee4Fiche.text = etape1.poignee4
    poignee5Fiche.text = etape1.poignee5
    }
    La syntaxe "if let" de Swift permet de faire d'une pierre deux coup : (1) tu ne rentres dans le "if" que si singlePatient.etape1 a une valeur (n'est pas nil), (2) et dans ce cas, à  l'intérieur du "if", cette valeur est accessible via la variable "etape1" (qui du coup n'est PLUS optionnelle). C'est ce qui est bien avec cette syntaxe, à  la fois ça vérifie que c'est pas nil, et en + dans ce cas là  ça extrait alors la valeur dans une variable non-optionelle pour que tu n'aies pas à  la unwrapper à  l'intérieur du "if" puisque si tu es entré dans le "if" c'est que forcément elle n'est pas nil de toute façon.

    C'est ce que j'explique dans mon article : si tu as ajouté un "!" dans ton code et que tu ne sais pas trop pourquoi, en tout cas que tu ne l'as ajouté que parce que Xcode t'a mis une erreur avant et dit de le rajouter pour régler le problème, sache que tu es en train de tuer des poneys.
  • DrakenDraken Membre
    septembre 2015 modifié #46


     


    sache que tu es en train de tuer des poneys.


     




    C'est juste des grosses bêtes qui puent et mordent. Pas très motivant. D'ailleurs, la seule fois qu'un poney se rend utile dans Le Trône De Fer, c'est en servant de casse-croûte à  un dragon. Sauver des chatons, ça c'est valorisant.


  • AliGatorAliGator Membre, Modérateur
    Draken toi du coup t'as dû aimer l'article que j'ai écrit ce WE alors ^^
  • Je viens de voir le titre, c'est vraiment que c'est alléchant.



  •  


    Plus besoin d'ajouter les ? à  la main dans les classes modèle.


     


    Update for Xcode 7: This issue has been solved with Xcode 7 beta 2. Optional Core Data properties are now defined as optional properties in the managed object subclasses generated by Xcode. It is no longer necessary to edit the generated class definition.



     


    Super !! J'avais fais la remarque à  la sortie e Swift mais ils n'avaient jamais pris en compte le rapport de bug que j'avais envoyé, du moins ils ne le traitaient pas. ça va faire du bien !


  • J'ai lu ton article, où j'ai un peu du mal avec l'anglais, par contre je commence à  comprendre, et ton code (plus haut sans les "!")  marche nickel. Vive le optionnel bindings - hein c'est ça ? d;-)


  • AliGatorAliGator Membre, Modérateur

    J'ai lu ton article, où j'ai un peu du mal avec l'anglais

    Si tu préfères, il sera bientôt disponible en Chinois ;-)

    Par contre je commence à  comprendre, et ton code (plus haut sans les "!")  marche nickel. Vive le optionnel bindings - hein c'est ça ? d;-)

    Exactement ;)
Connectez-vous ou Inscrivez-vous pour répondre.