Disons que j'ai deux classes d'entité: SocialApp
etSocialAppType
Dans SocialApp
je un attribut: appURL
et une relation: type
.
Dans SocialAppType
J'ai trois attributs: baseURL
, name
et favicon
.
La destination de la SocialApp
relation type
est un enregistrement unique dans SocialAppType
.
Par exemple, pour plusieurs comptes Flickr, il y aurait un certain nombre d' SocialApp
enregistrements, chaque enregistrement contenant un lien vers le compte d'une personne. Il y aurait un SocialAppType
enregistrement pour le type "Flickr", que tous les SocialApp
enregistrements indiqueraient.
Lorsque je crée une application avec ce schéma, je reçois un avertissement indiquant qu'il n'y a pas de relation inverse entre SocialAppType
et SocialApp
.
/Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse
Ai-je besoin d'un inverse, et pourquoi?
la source
La documentation Apple a un excellent exemple qui suggère une situation où vous pourriez avoir des problèmes en n'ayant pas de relation inverse. Mappons-le dans ce cas.
Supposons que vous l'avez modélisé comme suit:
Notez que vous avez une relation à un appelée " type ", de
SocialApp
àSocialAppType
. La relation n'est pas facultative et comporte une règle de suppression «refuser» .Considérez maintenant ce qui suit:
Nous nous attendons à ce que cette sauvegarde de contexte échoue car nous avons défini la règle de suppression sur Refuser tandis que la relation n'est pas facultative.
Mais ici, la sauvegarde réussit.
La raison en est que nous n'avons pas établi de relation inverse . Pour cette raison, l'instance socialApp n'est pas marquée comme modifiée lorsque appType est supprimé. Aucune validation n'a donc lieu pour socialApp avant l'enregistrement (cela suppose qu'aucune validation n'est nécessaire car aucun changement n'est intervenu). Mais en fait, un changement s'est produit. Mais cela ne se reflète pas.
Si nous rappelons appType par
appType est nul.
Bizarre, non? Nous obtenons nul pour un attribut non optionnel?
Vous n'avez donc aucun problème si vous avez mis en place la relation inverse. Sinon, vous devez forcer la validation en écrivant le code comme suit.
la source
Je vais paraphraser la réponse définitive que j'ai trouvée dans More iPhone 3 Development par Dave Mark et Jeff LeMarche.
Apple vous recommande généralement de toujours créer et spécifier l'inverse, même si vous n'utilisez pas la relation inverse dans votre application. Pour cette raison, il vous avertit lorsque vous ne fournissez pas d'inverse.
Les relations ne sont pas obligées d'avoir un inverse, car il existe quelques scénarios dans lesquels la relation inverse pourrait nuire aux performances. Par exemple, supposons que la relation inverse contienne un très grand nombre d'objets. La suppression de l'inverse nécessite une itération sur l'ensemble qui représente l'inverse, ce qui affaiblit les performances.
Mais à moins que vous n'ayez une raison spécifique de ne pas le faire, modélisez l'inverse . Il aide Core Data à garantir l'intégrité des données. Si vous rencontrez des problèmes de performances, il est relativement facile de supprimer la relation inverse plus tard.
la source
La meilleure question est: "y a-t-il une raison de ne pas avoir d'inverse"? Core Data est vraiment un cadre de gestion de graphes d'objets, pas un cadre de persistance. En d'autres termes, son travail est de gérer les relations entre les objets dans le graphe d'objets. Les relations inverses rendent cela beaucoup plus facile. Pour cette raison, Core Data attend des relations inverses et est écrit pour ce cas d'utilisation. Sans eux, vous devrez gérer vous-même la cohérence du graphe d'objets. En particulier, les relations à plusieurs sans relation inverse sont très susceptibles d'être corrompues par les données de base, à moins que vous ne travailliez très dur pour que les choses fonctionnent. Le coût en termes de taille de disque pour les relations inverses est vraiment insignifiant par rapport à l'avantage qu'il vous en rapporte.
la source
Il existe au moins un scénario dans lequel un bon cas peut être fait pour une relation de données de base sans inverse: lorsqu'il existe déjà une autre relation de données de base entre les deux objets, qui gérera la maintenance du graphe d'objets.
Par exemple, un livre contient plusieurs pages, tandis qu'une page est dans un livre. Il s'agit d'une relation plusieurs à un bidirectionnelle. La suppression d'une page annule simplement la relation, tandis que la suppression d'un livre supprimera également la page.
Cependant, vous pouvez également souhaiter suivre la page en cours de lecture pour chaque livre. Cela peut être fait avec une propriété "currentPage" sur Page , mais vous avez besoin d'une autre logique pour vous assurer qu'une seule page du livre est marquée comme la page actuelle à tout moment. Au lieu de cela, établir une relation currentPage entre Book et une seule page garantira qu'il n'y aura toujours qu'une seule page en cours marquée, et en outre, cette page sera facilement accessible avec une référence au livre avec simplement book.currentPage.
Quelle serait la relation réciproque dans ce cas? Quelque chose de largement absurde. «myBook» ou similaire pourrait être rajouté dans l'autre sens, mais il ne contient que les informations déjà contenues dans la relation «livre» pour la page, et crée ainsi ses propres risques. Peut-être qu'à l'avenir, la façon dont vous utilisez l'une de ces relations sera modifiée, ce qui entraînera des changements dans la configuration de vos données de base. Si page.myBook a été utilisé dans certains endroits où page.book aurait dû être utilisé dans le code, il peut y avoir des problèmes. Une autre façon d'éviter cela de manière proactive serait également de ne pas exposer myBook dans la sous-classe NSManagedObject utilisée pour accéder à la page. Cependant, on peut soutenir qu'il est plus simple de ne pas modéliser l'inverse en premier lieu.
Dans l'exemple décrit, la règle de suppression pour la relation currentPage doit être définie sur "Aucune action" ou "Cascade", car il n'y a pas de relation réciproque avec "Nullify". (Cascade implique que vous extrayez chaque page du livre au fur et à mesure que vous le lisez, mais cela peut être vrai si vous avez particulièrement froid et avez besoin de carburant.)
Lorsqu'il peut être démontré que l'intégrité du graphe d'objets n'est pas menacée, comme dans cet exemple, et que la complexité et la maintenabilité du code sont améliorées, on peut affirmer qu'une relation sans inverse peut être la bonne décision.
la source
currentPage
être marqué commeOptional
?Bien que la documentation ne semble pas exiger d'inverse, je viens de résoudre un scénario qui entraînait en fait une "perte de données" en n'ayant pas d'inverse. J'ai un objet de rapport qui a une relation à plusieurs sur les objets à signaler. Sans la relation inverse, toute modification de la relation à plusieurs a été perdue lors du redémarrage. Après avoir inspecté le débogage des données de base, il était évident que même si j'enregistrais l'objet de rapport, les mises à jour du graphique d'objet (relations) n'étaient jamais effectuées. J'ai ajouté un inverse, même si je ne l'utilise pas, et voilà, ça marche. Donc, cela peut ne pas dire que c'est nécessaire, mais des relations sans inverses peuvent certainement avoir des effets secondaires étranges.
la source
Les inverses sont également utilisés pour
Object Integrity
(pour d'autres raisons, voir les autres réponses):De: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1
Le lien fourni vous donne des idées pour lesquelles vous devriez avoir un
inverse
ensemble. Sans cela, vous pouvez perdre des données / intégrité. En outre, la probabilité que vous accédiez à un objetnil
est plus probable.la source
Il n'y a pas besoin de relation inverse en général. Mais il y a peu de bizarreries / bogues dans les données de base où vous avez besoin d'une relation inverse. Il y a des cas où des relations / objets disparaissent, même s'il n'y a pas d'erreur lors de l'enregistrement du contexte, s'il manque une relation inverse. Vérifiez cet exemple , que j'ai créé pour illustrer les objets manquants et comment contourner le problème, tout en travaillant avec les données de base
la source