Mise à  jour d'un modèle, synchronisation et doublons

muqaddarmuqaddar Administrateur
août 2014 modifié dans Objective-C, Swift, C, C++ #1

Salut,


 


Ce n'est pas la première fois que ça m'arrive et je cherche "LA" bonne technique pour mettre à  jour un modèle et ses données, et ne pas avoir de doublons après une synchronisation.


 


Prenons un exemple, avec un iPhone et un iPad qui synchronisent leurs données.


 


Sur l'iPad, l'utilisateur lance la nouvelle version de mon application.


Celle-ci créé, au lancement, une nouvelle table et la remplit à  partir d'une autre table.


Pas de synchronisation lancée sur l'iPad.


 


Sur l'iPhone, l'utilisateur lance la nouvelle version de mon application.


Il se passe la même chose, la nouvelle table est remplie à  partir de la précédente.


 


Sauf que sur les 2 devices, tous les éléments créés ont des UUID différents maintenant.


 


Si je synchronise des deux côtés, j'aurais tout en double... bien que les UUID des éléments de la table originale soient les mêmes avant cette nouvelle version.


 


--


 


Pour être plus concret, je vous expose mon problème.


 


J'ai actuellement une table "pairings" qui enregistre des associations de mets (aux vins).


Pour éviter les répétitions de mets associés (dans un même device), j'ajoute dans ma nouvelle version une table "dishes" qui enregistrera tous les mets, et j'ajoute une colonne dish_id à  ma table originale "pairings" à  laquelle ils se rapportent. Comme ça, sur un même device, je n'ai plus de doublons/triplons/... de mets. "pairings" est maintenant une table "n,n" qui ne contient plus de nom de met.


 


Donc au lancement de la prochaine version, je crée la table "dishes" et la remplit comme il faut à  partir de pairings, et je mets à  jour "pairings" avec le dish_id créé. Super.


 


Mais mon utilisateur a la même base sur son autre device, et au lancement, il va se produire la même chose... à  ce stade tout est bon.


 


Mais, l'utilisateur va synchroniser, et paf, on se retrouvera avec des doublons sur les 2 devices dans la table "dishes". (pour la table pairings, ce n'est pas un problème, c'est la dernière modifiée qui écrasera les  anciens enregistrements).


 


Donc, comment éviter ce comportement ? SI l'utilisateur a 4 devices, il y aurait des quadruplons... ;)


Le fond du problème étant que les UUID de la table "dishes" sont différents sur chaque device.


 


--


 


Une idée "pourrie" serait de vérifier si l'UUID de chaque "dish" se rapporte bien à  un "pairing -> dish_uuid" après chaque synchronisation, et si ce n'est le cas de le supprimer.

Réponses

  • AliGatorAliGator Membre, Modérateur

    1) Ca me fait toujours drôle de lire tes messages où, au fur et à  mesure de ma lecture, je réalise à  chaque fois que, ah oui c'est vrai, tu n'utilises pas CoreData mais fait tout à  la main avec une base SQL... mon pauvre ! Là  où CoreData propose déjà  tout ce qu'il faut côté merging policies et t'éviterai ce genre de prise de tête...


     


    2) Cependant, si tu as des risques de doublons, c'est que ton UUID n'est pas une bonne Primary Key peut-être (n'identifie pas de façon assez unique les éléments). Ou alors qu'il faut l'unifier lors de la synchro (ne pas faire ton INSERT OR UPDATE basé sur la PK mais sur un autre élément unifiant (peut-être une chaà®ne et peut-être pas indexée pour le coup, mais bon c'est que lors de la synchro en mm temps).


     


    Pour toi, quand considères-tu que tu as un doublon ? Je veux dire, quand considères-tu qu'il y a un même pairing, ou que 2 plats sont identiques, etc ? En te posant cette question, tu auras la réponse de savoir quel peut être ton élément unifiant, en particulier à  utiliser lors de la synchro (peut-etre le même que lors de ton CRUD de tous les jours, peut-être un différent car pour des questions de performances lors de l'utilisation en CRUD de ton appli tu préfèreras un identifiant unique type PK qui soit numérique et indexé, alors que lors de ta synchro tu auras des problématiques de ré-uniquéfier tes éléments).


     


    Si pour toi un pairing qui apparaà®t en doublon c'est un pairing qui a le même couple (plat, vin), alors c'est sur ce critère qu'il faut faire ton INSERT OR UPDATE lors de ta synchro.


  • muqaddarmuqaddar Administrateur


    1) Ca me fait toujours drôle de lire tes messages où, au fur et à  mesure de ma lecture, je réalise à  chaque fois que, ah oui c'est vrai, tu n'utilises pas CoreData mais fait tout à  la main avec une base SQL... mon pauvre ! Là  où CoreData propose déjà  tout ce qu'il faut côté merging policies et t'éviterai ce genre de prise de tête...




     


    Si je crée une table C à  partir de la table B et garde la table B pour servir d'associations entre A et C, je ne vois vraiment pas ce qui pourrait empêcher de créer des doublons sur chaque device, même avec Core Data... car il n'est pas au courant de ce qui a été fait sur l'autre device au moment de la migration.


     




    2) Cependant, si tu as des risques de doublons, c'est que ton UUID n'est pas une bonne Primary Key peut-être (n'identifie pas de façon assez unique les éléments). Ou alors qu'il faut l'unifier lors de la synchro (ne pas faire ton INSERT OR UPDATE basé sur la PK mais sur un autre élément unifiant (peut-être une chaà®ne et peut-être pas indexée pour le coup, mais bon c'est que lors de la synchro en mm temps).


     


    Pour toi, quand considères-tu que tu as un doublon ? Je veux dire, quand considères-tu qu'il y a un même pairing, ou que 2 plats sont identiques, etc ? En te posant cette question, tu auras la réponse de savoir quel peut être ton élément unifiant, en particulier à  utiliser lors de la synchro (peut-etre le même que lors de ton CRUD de tous les jours, peut-être un différent car pour des questions de performances lors de l'utilisation en CRUD de ton appli tu préfèreras un identifiant unique type PK qui soit numérique et indexé, alors que lors de ta synchro tu auras des problématiques de ré-uniquéfier tes éléments).


     


    Si pour toi un pairing qui apparaà®t en doublon c'est un pairing qui a le même couple (plat, vin), alors c'est sur ce critère qu'il faut faire ton INSERT OR UPDATE lors de ta synchro.




     


    Ce qu'il faudrait faire, c'est ne pas migrer un "pairing" puis un "dish", mais migrer un pairing qui "encapsule" un dish, de manière à  écraser le dish nouvellement créé sur l'autre device.

  • AliGatorAliGator Membre, Modérateur


    Si je crée une table C à  partir de la table B et garde la table B pour servir d'associations entre A et C, je ne vois vraiment pas ce qui pourrait empêcher de créer des doublons sur chaque device, même avec Core Data... car il n'est pas au courant de ce qui a été fait sur l'autre device au moment de la migration.


     


     


    Ce qu'il faudrait faire, c'est ne pas migrer un "pairing" puis un "dish", mais migrer un pairing qui "encapsule" un dish, de manière à  écraser le dish nouvellement créé sur l'autre device.




    Parce que CoreData est un modèle de Graphe Objets, et pas un modèle de Base de Données. Tu n'as pas besoin d'avoir une "table intermédiaire" "pairing" en plus de ta table "dish" parce que tu aurais une association N-N. CoreData fonctionne sur le système de "RelationShips" et gère tout seul parfaitement les associations N-N sans qu'on ait besoin de créer des tables ou entités intermédiaires. On n'a jamais de table de pairing en CoreData.


     


    Du coup si tu avais CoreData, il ferait un merge des dish (avec la mergePolicy que tu as choisie, selon la PrimaryKey qui va bien au besoin), et ensuite il se débrouillerait tout seul du côté des relationShips lors de ce merging. Mais là  c'est toi qui gère ta table de pairing, donc c'est toi qui doit te taper tout ce boulot.

  • muqaddarmuqaddar Administrateur


    Parce que CoreData est un modèle de Graphe Objets, et pas un modèle de Base de Données. Tu n'as pas besoin d'avoir une "table intermédiaire" "pairing" en plus de ta table "dish" parce que tu aurais une association N-N. CoreData fonctionne sur le système de "RelationShips" et gère tout seul parfaitement les associations N-N sans qu'on ait besoin de créer des tables ou entités intermédiaires. On n'a jamais de table de pairing en CoreData.


     


    Du coup si tu avais CoreData, il ferait un merge des dish (avec la mergePolicy que tu as choisie, selon la PrimaryKey qui va bien au besoin), et ensuite il se débrouillerait tout seul du côté des relationShips lors de ce merging. Mais là  c'est toi qui gère ta table de pairing, donc c'est toi qui doit te taper tout ce boulot.




     


    Oui, mais à  te lire, je suis content de mon choix, car comment porter cela sur une appli web (ce qui est mon cas), où je suis content d'avoir mes 2 tables pairings et dishes.

  • Les infos contenu dans la table dish sont saisies par l'utilisateur je suppose ?


  • muqaddarmuqaddar Administrateur


    Les infos contenu dans la table dish sont saisies par l'utilisateur je suppose ?




     


    Oui. 


    Mais ce n'est pas le problème pour les nouveaux "dishes" saisis à  partir de la version de l'app qui arrive.


     


    Le problème, c'est la migration de l'ancien système vers le nouveau, donc les anciens pairings modifiés (wine/pairings) et convertis vers un système (wine/pairings/dish).

  • Il ne serait pas possible de calculer un hash sur le contenu du dish et de s'en servir pour éviter de créer des doublons.
  • muqaddarmuqaddar Administrateur


    Il ne serait pas possible de calculer un hash sur le contenu du dish et de s'en servir pour éviter de créer des doublons.




     


    Tu peux développer, je ne suis pas.


    Et éviter de créer des doublons à  la synchro ou à  la mise à  jour ?

  • En fait au lieu de se baser sur l'id du record de la table dish comme "identifiant unique" un id généré "manuellement" (et sauvé en base pour éviter de tout recalculer) fonction du contenu du record pourrait être utilisé à  la place. un MD5 ou SHA1 semble être largement suffisant. L'unicité de record quelque soit la base de données est ainsi assuré et peut être utilisé comme clé.


     


    Maintenant s'il faut assuré l'unicité de chaque record de la table dish mais fonction aussi d'une autre table, l'idée serait alors d'utiliser un identifiant unique (aussi généré) pour l'enregistrement de l'autre table et de l'ajouter au calcul du hash de la table dish.


     


    Je n'ai pas toute les données en main et j'imagine la table dish comme étant simplement constitué d'un id (généré par SQLite) et d'un champ TEXT. Mais il pourrait y avoir 10 colonnes le principe resterait le même.


     


    Reste l'impact sur le temps de synchro...


     


    Bon vu l'heure aussi j'ai le cerveau en vrac... il peut y avoir des incohérences.


  • muqaddarmuqaddar Administrateur

    Que ce soit ma table "pairings" ou "dishes", elles ont toutes déjà  un id (qui est en fait déjà  un identifiant unique multi-devices UUID).


     


    Je comprends ton idée de hash, et en gros, ça revient à  migrer "l'association" plutôt que chaque élément séparé.


    Le problème, c'est que ça me fait casser ma logique de synchro avec ce cas particulier pour ces 2 tables (j'ai 12 tables en tout).




  • Tu peux développer, je ne suis pas.


    Et éviter de créer des doublons à  la synchro ou à  la mise à  jour ?




     


    Les deux en fait.


     


     




    Que ce soit ma table "pairings" ou "dishes", elles ont toutes déjà  un id (qui est en fait déjà  un identifiant unique multi-devices UUID).


     


    Je comprends ton idée de hash, et en gros, ça revient à  migrer "l'association" plutôt que chaque élément séparé.


    Le problème, c'est que ça me fait casser ma logique de synchro avec ce cas particulier pour ces 2 tables (j'ai 12 tables en tout).




     


    Les id (donc ici UUID) sont unique mais, comme tu l'a précisé dans le post d'introduction, "Le fond du problème étant que les UUID de la table "dishes" sont différents sur chaque devise". L'utilisation d'un hasch, pour la table "dishes", pourrait te servir à  générer un id identique à  contenu équivalent quelque soit le device.  

  • muqaddarmuqaddar Administrateur


    L'utilisation d'un hasch, pour la table "dishes", pourrait te servir à  générer un id identique à  contenu équivalent quelque soit le device.  




     


    OK, j'ai compris. Merci.


    Je vais voir comment je peux ajouter ce paramètre à  ma synchronisation, sans trop changer de choses dans le moteur.

Connectez-vous ou Inscrivez-vous pour répondre.