En admettant que ton code soit bon, la seule explication c'est que tes relations n'ont pas été établies comme tu l'imagines lors de l'import de ta base existante.
Pour le savoir tu fais un fetch tout simple sans predicate sur ton entité PROJECT et pour chaque PROJECT, tu parcours la relation allotement_bidule à l'aide d'un "for". Là tu vas bien voir si tes objets sont liés.
(Tu sais que si tu fais un valueForKey:@allotement_bidule sur tes objets de type PROJECT tu vas récupérer un NSSet.)
En admettant que ton code soit bon, la seule explication c'est que tes relations n'ont pas été établies comme tu l'imagines lors de l'import de ta base existante.
Pour le savoir tu fais un fetch tout simple sans predicate sur ton entité PROJECT et pour chaque PROJECT, tu parcours la relation allotement_bidule à l'aide d'un "for". Là tu vas bien voir si tes objets sont liés.
(Tu sais que si tu fais un valueForKey:@allotement_bidule sur tes objets de type PROJECT tu vas récupérer un NSSet.)
Lorsque je créé une requête pour récupérer pour afficher les ALLOTEMENT_PROJET_TICKET, les données sont bien récupérées.
Par contre lorsque je récupère des projets et que j'affiche leur relation a_projetc.allotement_projet_ticket_list_rel,
le NSSet est vide. La relation ne se fait pas entre le PROJET et le ALLOTEMENT_PROJET_TICKET.
En cherchant un peu, j'ai découvert que ces sous-classes de NSManagedObject ont été générées par Xcode alors que j'ai ajouté la relation ultérieurement dans le modèle Core Data et sa déclaration dans le code à la main.
Si l'ajout est correct, alors non, c'est pas magique.
Apres, si tu t'es trompé de type (NSSet ou NSOrderedSet) ou d'orthographe dans le nom de la relation, alors peut-être.
Si tu n'as pas ajouté de code, tu peux re-générer les classes pour voir (fais une copie ou un commit de ton projet si tu n'es pas sur de toi avant).
Bon c'est pas magique mais c'est quand même un peu mystérieux et parfois buggé (comme dans le cas des NSOrderedSet), donc ce que je fais maintenant par rapport à ces problèmes de classes générées, c'est que je ne modifie jamais le code généré pour les dérivés de NSManagedObject. Si j'ai besoin de rajouter du code sur ces objets, j'utilise des categories.
Bon c'est pas magique mais c'est quand même un peu mystérieux et parfois buggé (comme dans le cas des NSOrderedSet), donc ce que je fais maintenant par rapport à ces problèmes de classes générées, c'est que je ne modifie jamais le code généré pour les dérivés de NSManagedObject. Si j'ai besoin de rajouter du code sur ces objets, j'utilise des categories.
Oui c'est une bonne méthode.
Une autre alternative existe, c'est d'utiliser l'outil tierce mogenerator, un outil qui permet de générer les fichiers de classe des entitées de ton modèle CoreData, comme le fait Xcode quand tu sélectionnes tes entitées et lui demande via le menu adéquat, sauf qu'au lieu de générer un fichier "Toto.h" et "Toto.m" pour l'entité Toto, il génère/écrase "_Toto.h" et "_Toto.m" qui déclarent une classe "_Toto", et si "Toto.h" n'existe pas, il le crée avec "@interface Toto : _Toto".
L'objectif est que tu ne modifies que Toto.h / Toto.m et ajoute tes trucs à toi dans ces fichiers, et ne touche pas à "_Toto.h/m" qui contient le code généré. Si tu modifies ton modèle CoreData et réexécute mogenerator, ça va regénérer "_Toto.h/m" mais ne va pas toucher à "Toto.h/m" qui contient ton code, donc ne va rien écraser de ce que tu auras ajouté.
Une relation entre des entités CoreData est exactement le même concept d'une relation entre 2 tables dans une BDD relationnelle, ou au pattern de composition ou d'aggrégation classique en POO.
Je présenterai rapidement cela lors de ma prez aux CocoaHeads Rennes demain si ça te tente...
Une relation entre des entités CoreData est exactement le même concept d'une relation entre 2 tables dans une BDD relationnelle, ou au pattern de composition ou d'aggrégation classique en POO.
Je présenterai rapidement cela lors de ma prez aux CocoaHeads Rennes demain si ça te tente...
ça aurait été avec plaisir mais demain je bosses sur Paris.
Existe-t-il un podcast, playlist Youtube, ... des sessions ? je n'ai vu que les slides
Les relations Core Data gérées par des NSSet sont censées se remplir automatiquement ou il faut ajouter les éléments à la main ?
Il y aura un screencast video après coup, on le fait à chaque fois (tu peux regarder les vidéos des sessions précédentes, on les poste sur cocoaheads.fr et vimeo)
Pour ta question, les relations CoreData se remplissent automatiquement... après bien sûr faut affecter un bout de la relation, mais si tu le fais la relation inverse est automatiquement remplie.
Par exemple imaginons que tu as une entité Company et une entité Person, avec une relation Person->Company nommée "employer" et la relation to-many inverse correspondante Company->Person nommée "employees". Si tu crées 2 Company, puis 5 objets Person, il ne va pas tout seul savoir à quelle Company ils appartiennent tant que tu n'as aucunement relié les 2. Pour relier chaque Person avec la Company qui l'emploie, tu as le choix :
soit tu affectes la propriété "employer" de chaque objet Person à l'objet Company correspondant à son employeur
soit tu ajoutes l'objet Person a la Company, en utilisant les méthodes de la classe Company que t'aura généré CoreData, comme [company addEmployees:[NSSet setWithArray:@[person1, person2, person4]]];
Dans tous les cas si tu fais une de ces 2 actions (lier la Company à la Person ou ajouter la Person à la company, au choix) pas besoin de faire l'autre. Dès que tu as affecté une Company à la propriété "employer" d'un objet Person, cet objet Person est ajouté au NSSet "employees" de cette Company. Donc dans ce sens oui les NSSet se remplissent automatiquement (du moins tout ça c'est à condition que tu aies correctement indiqué dans ton modèle que "Company.employees" était la relation inverse de "Person.employer" bien sûr).
Les relations sont ce qui constituent ton réseau d'objets dans Core Data.
Les relations peuvent exprimer la partie métier de ton application : Par exemple, dans une application type de gestion de comptes bancaires, tu vas avoir plusieurs relations qui vont te permettre de lier un compte bancaire avec ses opérations bancaires.
Pourquoi partir dans ce sens et pas plutôt fonctionner dans le sens naturel des choses, dans l'ordre inverse ?
En particulier, quel est l'intérêt d'avoir une propriété "project_uuid" dans ton entité Ticket, alors que tu as justement une relation entre Ticket et Project et que Project a déjà un attribut "_uuid" ? Du coup à partir d'un ticket si tu veux récupérer le project_uuid tu peux déjà récupérer le projet puis sont UUID, donc faire "self.project._uuid" !
Donc pour moi l'idée n'est pas d'affecter la propriété "project_uuid" à ton ticket et que ça t'ajoute le ticket au projet (avec le code additionnel que tu as eu à écrire), mais plutôt l'inverse, récupérer le projet avec cet UUID et l'affecter à la relationship "project" de ton entité "ticket".
Donc en gros au lieu d'avoir à écrire tout ton code que tu as mis au dessus, et de faire
(NB: Ce code suppose que tu utilises MagicalRecord qui te permet d'utiliser des méthodes "findFirstByAttribute:withValue:" pour gagner en simplicité, perso je peux plus m'en passer)
Voir ma session des CocoaHeads Rennes #13 sur le sujet où justement j'ai dans ma présentation un exemple illustrant cela (pour associer une personne à une session à partir de son nom et prénom, la créer en base si elle n'existe pas, etc, le tout en 3 lignes grace à MagicalRecord)
c'est l'entité ALLOTEMENT_PROJET_TICKET qui a une propriété project_uuid et non l'entité TICKET.
J'ai l'impression en voyant le nom de ta table que tu as trop raisonné en mode "Base de Données" avec une "Table" que tu as dû créer juste pour faire ta relation Many-To-Many. Alors qu'en CoreData on peut directement faire des relations *-* entre les Entities y'a pas besoin d'une "Table" intermédiaire. C'est un Modèle de Données Objets, pas un Modèle de Base de Données.
Je ne trouve pas le lien vers le screencast. Tu pourrais me le partager stp ?
En fait il n'est pas encore dispo en ligne, il faut attendre (ou alors fallait venir à la session ^^)
Ok. Mais en tout cas ça explique pourquoi tu doit te compliquer la vie à dupliquer le travail que normalement CoreData fait pour toi, puisque normalement les "RelationShips" sont justement faites pour créer des relations (One-To-One ou One-To-Many ou Many-To-Many) gérées automatiquement, contrairement aux BDD où il te faut une table intermédiaire pour gérer les relations Many-To-Many.
Là avec la "Table" (Entity) intermédiaire et inutile que tu as dans ton CoreData, bah du coup tu es obligé d'ajouter du glue code comme tu as fait pour coller avec la redondance de données que tu as dans ta base (relationship ET table intermédiaire avec champs comme project_uuid)... donc des entités en plus dans ton CoreData et du code en plus à écrire et de la complexification... tout ça pour rien ^^
Réponses
Fais voir un peu l'ensemble de ton code pour ce que tu viens de faire.
Et si tu fais un fetch sur chaque type d'entité sans mettre de predicate, est-ce que tu récupères bien le nombre d'items attendus ?
Avec ce code :
je récupère bien les bonnes valueurs
En admettant que ton code soit bon, la seule explication c'est que tes relations n'ont pas été établies comme tu l'imagines lors de l'import de ta base existante.
Pour le savoir tu fais un fetch tout simple sans predicate sur ton entité PROJECT et pour chaque PROJECT, tu parcours la relation allotement_bidule à l'aide d'un "for". Là tu vas bien voir si tes objets sont liés.
(Tu sais que si tu fais un valueForKey:@allotement_bidule sur tes objets de type PROJECT tu vas récupérer un NSSet.)
Lorsque je créé une requête pour récupérer pour afficher les ALLOTEMENT_PROJET_TICKET, les données sont bien récupérées.
Par contre lorsque je récupère des projets et que j'affiche leur relation a_projetc.allotement_projet_ticket_list_rel,
le NSSet est vide. La relation ne se fait pas entre le PROJET et le ALLOTEMENT_PROJET_TICKET.
En cherchant un peu, j'ai découvert que ces sous-classes de NSManagedObject ont été générées par Xcode alors que j'ai ajouté la relation ultérieurement dans le modèle Core Data et sa déclaration dans le code à la main.
Cela peut-il poser un problème ?
Si l'ajout est correct, alors non, c'est pas magique.
Apres, si tu t'es trompé de type (NSSet ou NSOrderedSet) ou d'orthographe dans le nom de la relation, alors peut-être.
Si tu n'as pas ajouté de code, tu peux re-générer les classes pour voir (fais une copie ou un commit de ton projet si tu n'es pas sur de toi avant).
Bon c'est pas magique mais c'est quand même un peu mystérieux et parfois buggé (comme dans le cas des NSOrderedSet), donc ce que je fais maintenant par rapport à ces problèmes de classes générées, c'est que je ne modifie jamais le code généré pour les dérivés de NSManagedObject. Si j'ai besoin de rajouter du code sur ces objets, j'utilise des categories.
Oui c'est une bonne méthode.
Une autre alternative existe, c'est d'utiliser l'outil tierce mogenerator, un outil qui permet de générer les fichiers de classe des entitées de ton modèle CoreData, comme le fait Xcode quand tu sélectionnes tes entitées et lui demande via le menu adéquat, sauf qu'au lieu de générer un fichier "Toto.h" et "Toto.m" pour l'entité Toto, il génère/écrase "_Toto.h" et "_Toto.m" qui déclarent une classe "_Toto", et si "Toto.h" n'existe pas, il le crée avec "@interface Toto : _Toto".
L'objectif est que tu ne modifies que Toto.h / Toto.m et ajoute tes trucs à toi dans ces fichiers, et ne touche pas à "_Toto.h/m" qui contient le code généré. Si tu modifies ton modèle CoreData et réexécute mogenerator, ça va regénérer "_Toto.h/m" mais ne va pas toucher à "Toto.h/m" qui contient ton code, donc ne va rien écraser de ce que tu auras ajouté.
Je confirme que mogenerator est super.
Un peu compliqué à mettre en place, mais après c'est cool et facile.
Bon,
j'ai re-généré les sous-classes NSManagedObject mais sans succès.
Je dois faire un truc mal mais je ne sais pas quoi.
Quelqu'un peut m'expliquer d'ailleurs ce qu'est une relation Core Data, son utilité, ... ?
J'ai cherché sur internet et la doc Apple mais sans succès. Le concept reste flou pour moi
Je présenterai rapidement cela lors de ma prez aux CocoaHeads Rennes demain si ça te tente...
ça aurait été avec plaisir mais demain je bosses sur Paris.
Existe-t-il un podcast, playlist Youtube, ... des sessions ? je n'ai vu que les slides
Les relations Core Data gérées par des NSSet sont censées se remplir automatiquement ou il faut ajouter les éléments à la main ?
Pour ta question, les relations CoreData se remplissent automatiquement... après bien sûr faut affecter un bout de la relation, mais si tu le fais la relation inverse est automatiquement remplie.
Par exemple imaginons que tu as une entité Company et une entité Person, avec une relation Person->Company nommée "employer" et la relation to-many inverse correspondante Company->Person nommée "employees".
Si tu crées 2 Company, puis 5 objets Person, il ne va pas tout seul savoir à quelle Company ils appartiennent tant que tu n'as aucunement relié les 2. Pour relier chaque Person avec la Company qui l'emploie, tu as le choix :
Donc dans ce sens oui les NSSet se remplissent automatiquement (du moins tout ça c'est à condition que tu aies correctement indiqué dans ton modèle que "Company.employees" était la relation inverse de "Person.employer" bien sûr).
Salut,
Les relations sont ce qui constituent ton réseau d'objets dans Core Data.
Les relations peuvent exprimer la partie métier de ton application : Par exemple, dans une application type de gestion de comptes bancaires, tu vas avoir plusieurs relations qui vont te permettre de lier un compte bancaire avec ses opérations bancaires.
Du style :
Ce qu'il manquait effectivement à mon modèle de donnée, c'était d'alimenter le NSSet "à la main" lors du paramétrage de mes objets de données.
Je donne un peu de code pour éviter les maux de tête aux débutant Core Data comme moi ;-)
Petite explication :
J'ai une relation entre un projet et des tickets : 3 sous-classes de NSManagedObject (PROJET, TICKET, ALLOTEMENT_PROJET_TICKET)
Lorsque les propriétés projet_uuid et ticket_uuid sont paramétrées, j'ajoute le ticket dans le NSSet (cf. - (void)addTicketToProject; )
Merci beaucoup à tous de m'avoir aidé à résoudre ce problème,
et à bientôt
En particulier, quel est l'intérêt d'avoir une propriété "project_uuid" dans ton entité Ticket, alors que tu as justement une relation entre Ticket et Project et que Project a déjà un attribut "_uuid" ?
Du coup à partir d'un ticket si tu veux récupérer le project_uuid tu peux déjà récupérer le projet puis sont UUID, donc faire "self.project._uuid" !
Donc pour moi l'idée n'est pas d'affecter la propriété "project_uuid" à ton ticket et que ça t'ajoute le ticket au projet (avec le code additionnel que tu as eu à écrire), mais plutôt l'inverse, récupérer le projet avec cet UUID et l'affecter à la relationship "project" de ton entité "ticket".
Donc en gros au lieu d'avoir à écrire tout ton code que tu as mis au dessus, et de faire Pour moi tu peux enlever tout ton code additionnel de ton post au dessus et à la place écrire : (NB: Ce code suppose que tu utilises MagicalRecord qui te permet d'utiliser des méthodes "findFirstByAttribute:withValue:" pour gagner en simplicité, perso je peux plus m'en passer)
Voir ma session des CocoaHeads Rennes #13 sur le sujet où justement j'ai dans ma présentation un exemple illustrant cela (pour associer une personne à une session à partir de son nom et prénom, la créer en base si elle n'existe pas, etc, le tout en 3 lignes grace à MagicalRecord)
c'est l'entité ALLOTEMENT_PROJET_TICKET qui a une propriété project_uuid et non l'entité TICKET.
Je ne trouve pas le lien vers le screencast. Tu pourrais me le partager stp ?
Alors qu'en CoreData on peut directement faire des relations *-* entre les Entities y'a pas besoin d'une "Table" intermédiaire. C'est un Modèle de Données Objets, pas un Modèle de Base de Données.
En fait il n'est pas encore dispo en ligne, il faut attendre (ou alors fallait venir à la session ^^)
Le modèle est en effet fortement inspiré d'une base de donnée distante.
J'ai repris le projet en l'état et et je ne me sens pas d'opérer un refactoring aussi sérieux ...
Néanmoins lorsque j'aurai du temps devant moi ( ) ou au prochain projet, je modéliserai la couche modèle de manière plus adaptée à Core Data ^_^
Là avec la "Table" (Entity) intermédiaire et inutile que tu as dans ton CoreData, bah du coup tu es obligé d'ajouter du glue code comme tu as fait pour coller avec la redondance de données que tu as dans ta base (relationship ET table intermédiaire avec champs comme project_uuid)... donc des entités en plus dans ton CoreData et du code en plus à écrire et de la complexification... tout ça pour rien ^^