Core Data: relation to-many et faulting
Bonjour à tous,
Depuis quelques temps, je me prends la tête sur un point de conception de mon modèle de données avec Core Data. Pour faire simple : j'ai une entité " Search ", cette dernière représente une recherche (avec des critères et tout plein d'autres choses).
J'ai une autre entité " Offer ". Elle représente les offres issues d'une recherche (effectuée coté serveur). Pour la volumétrie : une recherche peut retourner jusqu'à 1 000 offres. Ces dernières sont téléchargées / parsées sur le principe d'une UITableView infinie (dès que l'utilisateur arrive à X rows de la fin, on télécharge les X résultats suivants).
Initialement, j'avais pensé au modèle de données ci-dessous. En effet, c'est le modèle le plus logique : une recherche peut retourner plein d'offres et une offre peut venir de plusieurs recherches.
Le problème
Je fais du parsing en batches (c'est à dire que je ne parse que 20 éléments à la fois lors du téléchargement des résultats). Seulement, dès que j'ajoute une offre dans la recherche, Core Data ne " faulte " plus la relation Search->Offer. Conséquence : une empreinte mémoire qui grimpe à chaque parsing (et quand on arrive à 800 offres, ça fait mal).
A priori, il n'est pas possible d'ajouter un objet à une relation to-many sans que Core Data ne " dé-faulte " par la relation inverse (c'est plutôt logique quand on y réfléchi).
Bref, c'est fonctionnel, mais d'un point de vue mémoire, ce n'est pas acceptable.
La solution ...
La solution, ce serait de ne plus avoir la relation inverse. Finalement, je n'en ai pas besoin. Il faut juste que je fasse gaffe à garder un graphe d'objets cohérent ... Ca devrait être faisable. D'ailleurs, ça marche au parsing ! L'empreinte mémoire redescend !
... qui ne marche pas
Mais le souci, c'est tout simplement que ça ne marche pas au requettage avec le modèle suivant :
Mais ce qui m'inquiète, c'est la seconde partie du message (en gras). Si je le comprends bien : un objet " search " ne peut pas être dans plusieurs " offer " à la fois ... Ca tombe bien, c'est ce qu'il semble se passer quand j'exécute tous ça ... En effet, quand je fais une requête avec le prédicat suivant : " searches CONTAINS(%@) " (pour récupérer des " offer ") : je n'ai qu'un seul résultat (plus ou moins aléatoire ...).
Conclusion :
Je suis à la recherche de toute idée ou toute piste pour avancer ... Soit continuer sur la voie qui me semblait être la solution, soit sur tout autre chemin.
Merci d'avance pour tout éclairage /smile.png' class='bbc_emoticon' alt=':)' />.
J.
Depuis quelques temps, je me prends la tête sur un point de conception de mon modèle de données avec Core Data. Pour faire simple : j'ai une entité " Search ", cette dernière représente une recherche (avec des critères et tout plein d'autres choses).
J'ai une autre entité " Offer ". Elle représente les offres issues d'une recherche (effectuée coté serveur). Pour la volumétrie : une recherche peut retourner jusqu'à 1 000 offres. Ces dernières sont téléchargées / parsées sur le principe d'une UITableView infinie (dès que l'utilisateur arrive à X rows de la fin, on télécharge les X résultats suivants).
Initialement, j'avais pensé au modèle de données ci-dessous. En effet, c'est le modèle le plus logique : une recherche peut retourner plein d'offres et une offre peut venir de plusieurs recherches.
Le problème
Je fais du parsing en batches (c'est à dire que je ne parse que 20 éléments à la fois lors du téléchargement des résultats). Seulement, dès que j'ajoute une offre dans la recherche, Core Data ne " faulte " plus la relation Search->Offer. Conséquence : une empreinte mémoire qui grimpe à chaque parsing (et quand on arrive à 800 offres, ça fait mal).
A priori, il n'est pas possible d'ajouter un objet à une relation to-many sans que Core Data ne " dé-faulte " par la relation inverse (c'est plutôt logique quand on y réfléchi).
Bref, c'est fonctionnel, mais d'un point de vue mémoire, ce n'est pas acceptable.
La solution ...
La solution, ce serait de ne plus avoir la relation inverse. Finalement, je n'en ai pas besoin. Il faut juste que je fasse gaffe à garder un graphe d'objets cohérent ... Ca devrait être faisable. D'ailleurs, ça marche au parsing ! L'empreinte mémoire redescend !
... qui ne marche pas
Mais le souci, c'est tout simplement que ça ne marche pas au requettage avec le modèle suivant :
Consistency Error: Offer.searches does not have an inverse; this is an advanced setting (no object can be in multiple destinations for a specific relationship)
Mais ce qui m'inquiète, c'est la seconde partie du message (en gras). Si je le comprends bien : un objet " search " ne peut pas être dans plusieurs " offer " à la fois ... Ca tombe bien, c'est ce qu'il semble se passer quand j'exécute tous ça ... En effet, quand je fais une requête avec le prédicat suivant : " searches CONTAINS(%@) " (pour récupérer des " offer ") : je n'ai qu'un seul résultat (plus ou moins aléatoire ...).
Conclusion :
Je suis à la recherche de toute idée ou toute piste pour avancer ... Soit continuer sur la voie qui me semblait être la solution, soit sur tout autre chemin.
Merci d'avance pour tout éclairage /smile.png' class='bbc_emoticon' alt=':)' />.
J.
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Pour information c'est exactement ce que fait CoreData avec les objet sous-jascent aux NSManagedObject (NSAtomicStore & cie).
Vu mon niveau et le de niveau des cours à l'époque, non, il saurait pas ^^
Puis bon, sécher mon cours pour aller faire le 4L Trophy, il a ma bénédiction ! C'est la seule chose pour laquelle je regrette de ne pas avoir continuer mes études :-p
Yoann,
Malheureusement, je dois garder mes offres en NSManagedObject. En effet, d'autres entités ont des relations qui pointent vers eux .
Non mais ça reste des NSManagedObject hein, va pas te refaire un backend CoreData ! C'est juste pour la culture que je disais que derrière NSManagedObject, les fault ne sont que des objet préchargé en lazy loading.
Toi tu reste sur des sous classe de NSManagedObject sauf que tu les préfabrique en leur donnant leurs données brutes ou l'URL pour les obtenir, et ensuite tu leur demande de se charger lorsque tu as besoin d'eux.
Hum, je ne suis pas certains de comprendre ... Ton idée serait que chaque objet "Offer" ne soit parsé (à partir du JSON) qu'à la demande (cà d à l'affichage par ex) ?
Exactement.
Ton JSON de réponse à la requête de recherche ne contient que les URL finales dans l'ordre d'affichage. Tu crée tes objets offre avec en unique données les URL et l'index de classement, puis tu lance le chargement des 20 premières et 20 suivantes, et ainsi de suite.
Tu peux même prévoir un système de gestion de concurrence des téléchargement pour éventuellement arrêter le téléchargement d'un set trop loin dans l'historique.
Et finalement, c'est un peu déjà ce que je fais (pour le lazy loading). Quand je parse mes réponse, j'ai un tableau d'offres (JSON), a chaque passe, je ne charge qu'un seul objet offre ...
Le souci est au moment ou j'ajoute l'offre à la recherche ... Du coup, CoreData unfaulte toutes les autres offres ... C'est vraiment ce point qui me fait ch***
Justement, l'idée est de rajouté ici une étape intermédiaire, tu crée tes NSMO vide et ensuite tu lis les données JSON associés. Tes objets existant déjà , tu ne repassera pas par un fault