CoreData Relationship (many to many)
Alak
Membre
Bonjour,
J'essaye d'ajouter une relation entre deux objets, et je me prend un :
Le model :
La method utilisé ajouté grâce a une "category" :
l'erreur arrive à :
Je suis quasiment sûr que mon objet category est bien du type (Categories *), avant d'exécuter la méthode je fait une vérification pour être sûr que category ne fait pas déjà partie des catégories de ce pictogramme.
Si ca peux aider, j'ai modifié la base SQLite derrière mon CoreData pour la pré-remplir. Mais jusqu'ici la base pré-rempli fonctionnais très bien.
Je ne comprend pas bien l'erreur, car elle parle de NSSet mais la méthode prend en argument un objet de type "Categories" et c'est elle qui est sensé l'ajouter au NSSet.
Merci d'avance pour votre aide.
J'essaye d'ajouter une relation entre deux objets, et je me prend un :
<br />
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSSet intersectsSet:]: set argument is not an NSSet'<br />
Le model :
<br />
@interface Pictograms : NSManagedObject<br />
@property (nonatomic) BOOL enabled;<br />
@property (nonatomic) BOOL humeur;<br />
@property (nonatomic) BOOL lock;<br />
@property (nonatomic, retain) NSString * name;<br />
@property (nonatomic) int16_t used;<br />
@property (nonatomic, retain) NSSet *categories;<br />
@property (nonatomic, retain) Sounds *sound;<br />
@property (nonatomic, retain) Images *image;<br />
@end<br />
@interface Pictograms (CoreDataGeneratedAccessors)<br />
- (void)addCategoriesObject:(Categories *)value;<br />
- (void)removeCategoriesObject:(Categories *)value;<br />
- (void)addCategories:(NSSet *)values;<br />
- (void)removeCategories:(NSSet *)values;<br />
@end<br />
La method utilisé ajouté grâce a une "category" :
<br />
- (void)addCategory:(Categories *)category {<br />
[self addCategoriesObject:category];<br />
Categories *sock = [Categories getSockCategory];<br />
if (self.categories.count > 0 && [self.categories containsObject:sock]) {<br />
[self removeCategoriesObject:sock];<br />
}<br />
}<br />
l'erreur arrive à :
<br />
[self addCategoriesObject:category];<br />
Je suis quasiment sûr que mon objet category est bien du type (Categories *), avant d'exécuter la méthode je fait une vérification pour être sûr que category ne fait pas déjà partie des catégories de ce pictogramme.
Si ca peux aider, j'ai modifié la base SQLite derrière mon CoreData pour la pré-remplir. Mais jusqu'ici la base pré-rempli fonctionnais très bien.
Je ne comprend pas bien l'erreur, car elle parle de NSSet mais la méthode prend en argument un objet de type "Categories" et c'est elle qui est sensé l'ajouter au NSSet.
Merci d'avance pour votre aide.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Pictograms -> Pictogram
Categories -> Category.
Du coup cela donnera :
-(void)addCategoriesObject: (Category*)value;
-(void)addCategories: (NSSet*)values;
A mon avis le bug n'est pas dans le code affiché ici.
Peut-être dans la définition du model, vérifie que tu n'as pas coché "ordered set" par exemple.
Sinon peux-tu fournir un peu plus de details sur la pile d'appel ?
Petite remarque : Mieux vaut nommer les entités au singulier. En effet, tu défini dans ton modèle un object et non pas une collection.
Une autre idée?
Après vérification, je suis sûr de bien passer un objet "Category" valide
NSMutableSet *theCategories : [self mutableSetValueForKey:@categories];
[theCategories addObject:category];
J'ai voulu vérifier dans mes codes comment je faisais mais je me suis rendu compte que je n'avais aucun many-to-many...
Mais dis moi, tes methodes addCategory et removeCategory ne seraient-elles pas dans un fichier extension ?
Peut-être qu'en interne, CoreData inclue ton objet dans NSSet pour passer par une méthode générique de fusion des NSSet (d'où intersectrect...). C'est pour essayer de comprendre un peu ça qu'il serait bien de voir une plus grande partie de la pile d'appel.
Tu n'utilises bien qu'un seul managedObjectContext pour récupérer tous tes managedObjects ?
C'est quand même assez osé de faire ça.
Peux-tu être certain que tes bases sont correctes ?
Par exemple, est-ce que tu peux partir d'une base vierge, créer un objet de chaque type (Pictogram et Category) manuellement et les lier en utilisant ta méthode ? Ensuite tu fais un save. Tu fais ça dans le applicationDidFinishLaunching par exemple.
Si cela fonctionne, tu fais pareil en partant de ta base pré-remplie.
Si cela fonctionne, tu fais pareil mais en prenant deux objets issus de ta base pré-remplie.
Voilà , c'est ce que je voulais dire au-dessus.
Tu gagneras sans doute du temps à générer ta base via du code dans ton application. Un code que tu ferai tourner dans le simulateur pour créer ta base initiale via CoreData.
Je fais les testes pour voir ou est le problème.
J'ai l'impression que les ne fonctionne pas correctement.
Dans ma "category" j'avais la méthode ci-dessous :
Hors une méthode avec le même nom doit être automatiquement généré par CoreData.
"[font=helvetica, arial, sans-serif]Mais dis moi, tes methodes addCategory et removeCategory ne seraient-elles pas dans un fichier extension ?"[/font]
/cliccool.gif' class='bbc_emoticon' alt=' ' />
Déterrage: je n'avais encore jamais utilisé les Ordered Set avec Core Data... et je suis tombé sur le même problème.
Ah, au fait, il s'agit d'un bug d'Apple. Qui traà®ne depuis plus de deux ans.
Et y'a un gars sympa qui a corrigé tout ça de façon relativement propre.
Je continue ton déterrage car j'ai une question.
Je viens de suivre le tuto ici : http://www.raywenderlich.com/934/core-data-tutorial-for-ios-getting-started
Il indique que si (par exemple) j'ai une classe SousProduit qui a une clé externe vers Produit, de rajouter un relationship dans la classe SousProduit. Jusque là c'est logique.
Par contre il dit aussi qu'Apple précaunise de faire le contraire aussi, c'est à dire une clé sousProduit dans Produit.
Or là c'est complètement fou pour moi (je fais beaucoup d'UML donc ca me choque!).
Est-ce que quelqu'un peut me confirmer que j'ai raison svp ?
A moins que je n'aie rien compris à CoreData !
CoreData n'est pas un gestionnaire de base de données dans le sens usuel. D'ailleurs on ne parle pas de clés (on ne définit pas une primary key par exemple) dans CoreData.
C'est un graphe d'objets.
Les relations inverses (si c'est bien cela dont tu parles) permettent à CoreData d'assurer l'intégrité des données à ta place.
Je confirme que tu as tort! Apple t'oblige à nommer la relation inverse, tu auras même un warning si tu ne le fais pas. Maintenant, je t'avoue que moi aussi, je trouve ça inhabituel, mais c'est bien pratique.
Merci pour les deux réponses.
Il faut que je m'éloigne d'UML
Donc pour faire en sorte que les deux se "comprennent", je mets la bonne "destination" pour les deux relationships.
A quoi sert alors le champ "Inverse" ?
EDIT : Je viens de voir sur le schéma qu'au lieu de faire 2 flèches différentes, il combine les deux. Mais quelle est la différence entre les deux ?
En fait tu fais bien deux flèches (deux relations), et c'est en indiquant que la seconde est inverse de la première que XCode n'en fait qu'une du genre <---> selon la cardinalité. Tu peux également faire une relation d'une entité sur elle-même.
On peut imaginer que Produit pointe sur lui même pour les sous produits (un sous produit n'est-il pas un produit en fin de compte ?).
La différence entre les deux quoi ?
C'est à toi d'indiquer le type de relation (to-one, two-many). Ainsi pour reprendre ton exemple Produit, tu auras Produit<---->>SousProduit (i.e. à un Produit correspond plusieurs SousProduit, et un SousProduit correspond à un et un seul Produit).
Dans tes relations tu exprimes aussi les Delete Rules. En spécifiant par exemple Cascade à la relation Produit---->>SousProduit ; si dans ton code tu supprimes un Produit, alors CoreData va automatiquement supprimer les SousProduit qui lui sont associés (ce n'est pas forcément efficace en terme de performances à partir d'un volume important de données, mais c'est une autre histoire).
Une voiture contient 4 roues, mais aussi chaque roue appartient à une voiture. Il faut spécifier la cardinalité dans les 2 sens, certes tu n'as qu'un trait entre les 2 entités en UML, pour indiquer une composition dans le cas que j'ai pris comme exemple, mais tu as une cardilaité de chaque côté quand même. Si tu dis juste que chaque roue appartient à une voiture sans préciser la cardinalité inverse tu oublies dans ton schema UML de spécifier que chaque voiture a exactement 4 roues. Et de spécifier aussi ce qui se passe si la voiture est détruite, est-ce que les roues le sont aussi, et vice-versa (Delete Rules).
De même si tu ne mets une cardinalité que d'un côté entre une entité "Personne" et une entité "Voiture", tu vas spécifier dans ton UML que une Maison peut être habitée par 0 ou plusieurs personnes (0-*), mais il faut aussi préciser en UML comme en CoreData si une personne peut avoir 0 maisons, ou qu'une seule, ou plusieurs. Bah les relations inverses, c'est tout à fait ça.
Heuuu Ali je n'ai pas dit le contraire. J'ai supposé qu'il parlait de la différence entre deux relations dans CoreData. Pas entre UML et CoreData. J'ai donc développé sur les options Core Data.
Exemple :
Voiture avec deux sous-entités : voiture de course et voiture normale.
Autre entité : Conducteur.
Je veux une relation conducteurDeCourse et une relation conducteurNormal sur Conducteur.
Je veux une relation voiture sur Conducteur.
Bon mon cas est un peu débile, mais j'ai été confronté à ce cas dans des cas concrets.
Si quelqu'un a déjà été confronté à cette question et à des idées...
Pourquoi ne pas créer une seule entité Voiture avec un attribut typeVoiture ?
Méthode qui doit répondre différemment selon le type de voiture.
Pourquoi évites-tu les entités abstraites ?
@colas2 oui j'ai déjà été confronté au problème, il n'y a pas de solution miracle à ma connaissance
Je m'en sortirai très bien avec une méthode qui accepte un enum en paramètre pour indiquer le type de voiture.
Parce que je trouve pas ça joli, et parce que j'ai eu de gros problèmes de performances avec. Finalement j'ai découvert après coup qu'Apple - dans une vidéo wwdc - déconseillait fortement l'usage d'entités abstraites.