Détection et résolution des conflits de contraintes
Les conflits de contraintes sont des conflits qui ne respectent pas les contraintes mises sur les éléments, par exemple la relation de dossiers ou l'emplacement de données portant le même nom dans un système de fichiers. Sync Framework fournit des applicateurs de modifications qui simplifient la résolution des conflits de contraintes.
Les conflits de contraintes sont détectés par le fournisseur de destination pendant la phase d'application des modifications de la synchronisation. Lorsque le fournisseur de destination détecte un conflit de contraintes, il le signale à l'applicateur de modifications. L'applicateur de modifications résout le conflit conformément à la stratégie de résolution de conflit définie pour la session ou à l'action de résolution de conflit définie par l'application pour le conflit spécifié. L'applicateur de modifications distribue ensuite tous les appels nécessaires au fournisseur de destination afin que celui-ci puisse appliquer le conflit résolu au réplica de destination.
Lorsqu'un fournisseur signale des conflits de contraintes et qu'il emploie un applicateur de modifications, il doit également fournir un journal des conflits qui permet à l'applicateur de modifications de traiter et d'enregistrer les conflits. Sync Framework fournit une implémentation en mémoire d'un journal des conflits pour les fournisseurs qui n'implémentent pas leur propre journal des conflits. Pour plus d'informations, consultez Journalisation et gestion des conflits.
Gardez à l'esprit que les conflits de contraintes ne peuvent pas être utilisés par un fournisseur qui utilise des filtres personnalisés ou le service d'application des modifications, sinon des résultats inattendus peuvent se produire.
Types de conflits de contraintes
Les conflits de contraintes dépendent du magasin de données utilisé par le réplica de destination et peuvent donc prendre de nombreuses formes différentes. Sync Framework distingue les trois types suivants de conflits de contraintes.
Un conflit de collision se produit lorsque l'élément ne peut pas être enregistré parce qu'il est en conflit avec un autre élément dans le magasin de destination, comme ce peut être le cas lorsque le fournisseur de source envoie un fichier portant le même nom et situé au même emplacement qu'un fichier qui existe déjà dans le réplica de destination.
Un conflit de parent manquant se produit lorsqu'un élément ne peut pas être enregistré dans un magasin de données hiérarchique parce qu'il requiert un élément parent qui n'existe pas, comme ce peut être le cas lorsque le fournisseur de source envoie un fichier à enregistrer dans un répertoire qui n'existe pas sur le réplica de destination.
D'autres conflits de contraintes se produisent lorsque l'élément à enregistrer ne respecte pas une contrainte du réplica de destination, comme ce peut être le cas lorsque le fournisseur de source envoie un fichier trop volumineux pour être enregistré sur le réplica de destination ou lorsque la modification va à l'encontre d'une logique métier sur le réplica de destination. Pour illustrer un conflit de logique métier, prenons un réplica à fidélité faible qui stocke deux unités de modification : name et country. Prenons également un réplica à fidélité élevée qui stocke trois unités de modification : name, state/province et country. Le réplica à fidélité élevée contient la logique métier qui vérifie le champ state/province par rapport au champ country, et ne stockera pas une modification qui ne passe pas le contrôle avec succès. Le réplica à fidélité faible joue le rôle de source et envoie un élément avec « USA » comme valeur de country. Le fournisseur de destination essaie d'appliquer la modification au réplica à fidélité élevée, mais sur ce dernier, le champ state/province de l'élément contient « Colombie britannique ». Par conséquent, la modification ne respecte pas la logique métier et provoque un conflit de contraintes.
Le fournisseur de destination sélectionne l'une des valeurs suivantes pour spécifier la raison d'un conflit de contraintes.
Raison du conflit de contraintes |
Description |
---|---|
Collision (pour le code managé), CCR_COLLISION (pour le code non managé) |
L'élément ne peut pas être enregistré car il est en conflit avec un autre élément du magasin, comme un élément qui porte le même nom qu'un élément existant. Le fournisseur doit spécifier l'ID de l'élément de destination comme ID d'élément en conflit. |
NoParent (pour le code managé), CCR_NOPARENT (pour le code non managé) |
L'élément ne peut pas être enregistré dans le magasin de données hiérarchique parce qu'il requiert un élément parent qui n'existe pas dans le magasin. Le fournisseur peut éventuellement spécifier l'ID du parent manquant comme ID d'élément en conflit. |
Other (pour le code managé), CCR_OTHER (pour le code non managé) |
L'élément ou l'unité de modification ne respecte pas une autre contrainte du réplica de destination. Le fournisseur peut éventuellement spécifier l'ID de l'élément en conflit comme ID d'élément en conflit. |
Détection et signalement des conflits de contraintes
La détection d'un conflit de contraintes dépend du magasin de données qui est utilisé par un réplica. Par conséquent, les conflits de contraintes doivent être détectés par le fournisseur de destination. Par exemple, un fournisseur qui représente un système de fichiers hiérarchique doit être en mesure de détecter des contraintes spécifiques au magasin qui sont mises sur des données persistantes, telles que l'emplacement, la désignation, la taille, etc.
Les conflits de contraintes sont détectés par le fournisseur de destination pendant la phase d'application des modifications de la synchronisation.
Code managé Les conflits de contraintes sont généralement détectés par le fournisseur de destination dans sa méthode SaveItemChange ou SaveChangeWithChangeUnits et signalés en appelant RecordConstraintConflictForItem ou RecordConstraintConflictForChangeUnit.
Code non managé Les conflits de contraintes sont généralement détectés par le fournisseur de destination dans sa méthode ISynchronousNotifyingChangeApplierTarget::SaveChange ou ISynchronousNotifyingChangeApplierTarget::SaveChangeWithChangeUnits et signalés en appelant ISaveChangeContext2::SetConstraintConflictOnChange ou ISaveChangeWithChangeUnitsContext2::SetConstraintConflictOnChangeUnit.
Lorsque l'applicateur de modifications reçoit un rapport d'un conflit de contraintes, il prend plusieurs actions :
Lorsque le conflit de contraintes est un conflit de collision, l'applicateur de modifications détermine si le conflit est un nouveau conflit, un conflit temporaire ou une propagation de la résolution de fusion. Pendant la phase de traitement du conflit, l'applicateur de modifications peut stocker temporairement le conflit dans le journal des conflits en appelant SaveConstraintConflict (pour le code managé) ou ISynchronousNotifyingChangeApplierTarget2::SaveConstraintConflict (pour le code non managé). L'applicateur de modifications supprime les conflits temporaires du journal à la fin de la session de synchronisation.
Il résout les conflits de collision conformément à la stratégie de résolution des conflits de collision définie pour la session ou à l'action de résolution de conflit définie par l'application. L'application est appelée pour déterminer l'action de résolution de conflit lorsque la stratégie de résolution des conflits de collision est définie à la valeur ApplicationDefined (pour le code managé) ou CCRP_NONE (pour le code non managé).
Il résout les conflits de contraintes de non-collision en fonction de l'action de résolution de conflit définie par l'application. Une stratégie de résolution de conflit ne peut pas être définie pour les conflits de contraintes de non-collision.
Résolution des conflits de contraintes
L'applicateur de modifications aide le fournisseur de destination à résoudre les conflits de contraintes en distribuant les appels à l'objet cible de l'applicateur de modifications spécifié par le fournisseur. Lorsqu'une stratégie de résolution des conflits de collision est spécifiée, l'applicateur de modifications l'utilise pour déterminer l'action de résolution de conflit appropriée qu'il doit prendre pour résoudre chaque conflit de collision qui se produit. Lorsque la résolution de conflit de collision personnalisée est spécifiée, l'applicateur de modifications signale le conflit de collision à l'application de synchronisation, laquelle à son tour spécifie l'action de résolution de conflit à prendre. Étant donné qu'une stratégie de résolution de conflit ne peut pas être spécifiée pour les conflits de contraintes de non-collision, l'applicateur de modifications signale à l'application chaque conflit de contraintes de non-collision qui se produit afin qu'elle puisse spécifier l'action de résolution de conflit à prendre. Dans tous les cas, l'applicateur de modifications appelle la méthode cible appropriée de l'applicateur de modifications, puis l'objet cible de l'applicateur de modifications effectue l'action, par exemple, enregistrer la modification dans le réplica ou enregistrer le conflit pour le traiter ultérieurement.
Spécification d'une stratégie de résolution des conflits de collision
L'application de synchronisation spécifie généralement une stratégie de résolution des conflits de collision avant le démarrage de la synchronisation.
Code managé L'application spécifie la stratégie en définissant une valeur pour la propriété CollisionConflictResolutionPolicy du fournisseur de destination.
Code non managé L'application spécifie la stratégie à l'aide d'un mécanisme personnalisé, tel qu'une interface personnalisée que l'application obtient en appelant QueryInterface sur l'objet du fournisseur de destination.
Le fournisseur de destination passe ainsi la stratégie de résolution des conflits de collision à la méthode ApplyChanges (pour le code managé) ou ISynchronousNotifyingChangeApplier2::ApplyChanges (pour le code non managé) de l'applicateur de modifications afin que celui-ci puisse distribuer correctement les méthodes à sa cible. La cible de l'applicateur de modifications est représentée par l'objet INotifyingChangeApplierTarget2 (pour le code managé) ou ISynchronousNotifyingChangeApplierTarget2 (pour le code non managé).
Stratégies de résolution des conflits de collision pour le code managé
Sync Framework définit les stratégies de résolution des conflits de collision suivantes pour le code managé.
Stratégie de résolution de conflit |
Description |
---|---|
La modification effectuée sur le réplica source gagne toujours. Sync Framework spécifie une action de résolution de conflit SourceWins. |
|
La modification effectuée sur le réplica de destination gagne toujours. Sync Framework spécifie une action de résolution de conflit DestinationWins. |
|
La modification envoyée du fournisseur de source est renommée afin qu'elle n'entre plus en conflit avec l'élément en conflit sur le réplica de destination, et la modification de la source est appliquée au réplica de destination. Sync Framework spécifie une action de résolution de conflit RenameSource. |
|
L'élément en conflit sur le réplica de destination est renommé afin qu'il n'entre plus en conflit avec la modification envoyée du fournisseur de source, et la modification de la source est appliquée au réplica de destination. Sync Framework spécifie une action de résolution de conflit RenameDestination. |
|
Les données de l'élément source sont combinées à l'élément de destination. Sync Framework spécifie une action de résolution de conflit Merge. |
|
L'applicateur de modifications signale à l'application de synchronisation chaque conflit de collision qui se produit, en utilisant l'événement ItemConstraint. L'application examine les éléments en conflit et spécifie l'action de résolution de conflit en appelant SetResolutionAction. |
Stratégies de résolution des conflits de collision pour le code non managé
Sync Framework définit les stratégies de résolution des conflits de collision suivantes pour le code non managé.
Stratégie de résolution de conflit |
Description |
---|---|
CCRP_SOURCE_PROVIDER_WINS |
La modification effectuée sur le réplica source gagne toujours. Sync Framework spécifie une action de résolution de conflit SCRA_ACCEPT_SOURCE_PROVIDER. |
CCRP_DESTINATION_PROVIDER_WINS |
La modification effectuée sur le réplica de destination gagne toujours. Sync Framework spécifie une action de résolution de conflit SCRA_ACCEPT_DESTINATION_PROVIDER. |
CCRP_RENAME_SOURCE |
La modification envoyée du fournisseur de source est renommée afin qu'elle n'entre plus en conflit avec l'élément en conflit sur le réplica de destination, et la modification de la source est appliquée au réplica de destination. Sync Framework spécifie une action de résolution de conflit SCRA_RENAME_SOURCE. |
CCRP_RENAME_DESTINATION |
L'élément en conflit sur le réplica de destination est renommé afin qu'il n'entre plus en conflit avec la modification envoyée du fournisseur de source, et la modification de la source est appliquée au réplica de destination. Sync Framework spécifie une action de résolution de conflit SCRA_RENAME_DESTINATION. |
CCRP_MERGE |
Les données de l'élément source sont combinées à l'élément de destination. Sync Framework spécifie une action de résolution de conflit SCRA_MERGE. |
CCRP_NONE |
L'applicateur de modifications signale à l'application de synchronisation chaque conflit de collision qui se produit, en utilisant l'événement ISyncConstraintCallback::OnConstraintConflict. L'application examine les éléments en conflit et spécifie l'action de résolution de conflit en appelant IConstraintConflict::SetConstraintResolveActionForChange ou IConstraintConflict::GetConstraintResolveActionForChangeUnit. |
Spécification de résolutions de conflits personnalisées
Une application peut indiquer qu'elle spécifiera une action de résolution de conflit pour chaque conflit de contraintes qui se produit. Pour ce faire, l'application s'inscrit afin de recevoir une notification des conflits de contraintes. Lorsqu'un conflit de contraintes est signalé, Sync Framework envoie une notification à l'application. L'application peut alors analyser le conflit et définir l'action de résolution de conflit appropriée.
Spécification de résolutions de conflits personnalisées en utilisant le code managé
Pour recevoir une notification des conflits de collision, une application effectue les actions suivantes avant de démarrer la synchronisation.
Elle inscrit un gestionnaire d'événements pour l'événement ItemConstraint du fournisseur de destination.
Elle définit la propriété CollisionConflictResolutionPolicy du fournisseur de destination à la valeur ApplicationDefined.
Si l'application a effectué ces étapes, l'applicateur de modifications déclenche l'événement ItemConstraint une fois pour chaque conflit de contraintes de collision signalé pendant la synchronisation.
Étant donné qu'une stratégie de résolution de conflit ne peut pas être spécifiée pour les conflits de contraintes de non-collision, l'applicateur de modifications déclenche également l'événement ItemConstraint une fois pour chaque conflit de contraintes de non-collision signalé.
Le gestionnaire d'événements de l'événement ItemConstraint reçoit un objet ItemConstraintEventArgs qui contient des métadonnées et des données d'élément relatives aux deux modifications en conflit. Le gestionnaire d'événements peut examiner ces deux modifications, modifier des métadonnées ou des données d'élément et définir l'action de résolution du conflit à l'aide de la méthode SetResolutionAction. L'applicateur de modifications traite ensuite le conflit et distribue l'appel approprié à l'objet cible de l'applicateur de modifications. Gardez à l'esprit que les seules actions de résolution de conflit valides pour les conflits de contraintes de non-collision sont SaveConflict et SkipChange.
Sync Framework fournit l'ensemble suivant d'actions de résolution de conflit de contraintes pour lesquelles l'applicateur de modifications gère la plupart du traitement.
Action de résolution de conflit |
Description |
Type de conflit concerné |
---|---|---|
La modification effectuée sur le réplica source gagne toujours. L'applicateur de modifications passe la modification à la méthode SaveItemChange et spécifie une action d'enregistrement DeleteConflictingAndSaveSourceItem. La modification de la source est appliquée au réplica de destination et l'élément de destination en conflit est supprimé de ce dernier. |
Les conflits de collision uniquement. |
|
La modification effectuée sur le réplica de destination gagne toujours. L'applicateur de modifications passe la modification de la source à la méthode SaveItemChange et spécifie une action d'enregistrement DeleteAndStoreTombstone. Le fournisseur de destination crée un objet tombstone pour la modification de la source. Lorsque la destination joue le rôle de la source dans une synchronisation ultérieure, elle énumère une modification qui représente la suppression de l'élément source, et le supprime ainsi de la communauté de synchronisation. |
Les conflits de collision uniquement. |
|
La modification envoyée du fournisseur de source est renommée afin qu'elle n'entre plus en conflit avec l'élément en conflit sur le réplica de destination, et la modification de la source est appliquée au réplica de destination. L'applicateur de modifications passe la modification à la méthode SaveItemChange et spécifie une action d'enregistrement RenameSourceAndUpdateVersionAndData. |
Les conflits de collision uniquement. |
|
L'élément en conflit sur le réplica de destination est renommé afin qu'il n'entre plus en conflit avec la modification envoyée du fournisseur de source, et la modification de la source est appliquée au réplica de destination. L'applicateur de modifications passe la modification à la méthode SaveItemChange et spécifie une action d'enregistrement RenameDestinationAndUpdateVersionData. |
Les conflits de collision uniquement. |
|
Les données de l'élément source sont combinées à l'élément de destination. L'applicateur de modifications passe les données de modification du réplica source à la méthode SaveItemChange et spécifie une action d'enregistrement ChangeIdUpdateVersionAndMergeData. Pour plus d'informations, consultez Fusion des éléments en conflit, ci-dessous. |
Les conflits de collision uniquement. |
|
Permet de consigner le conflit et de ne pas appliquer la modification. L'applicateur de modifications passe les données en conflit à la méthode SaveConstraintConflict, ce qui enregistre le conflit dans un journal des conflits. Pour plus d'informations sur la journalisation des conflits, consultez Journalisation et gestion des conflits. |
Tous les conflits de contraintes. |
|
Permet d'ignorer le conflit et de ne pas appliquer la modification. L'applicateur de modifications ne passe pas les données en conflit au fournisseur de destination. |
Tous les conflits de contraintes. |
Spécification de résolutions de conflits personnalisées en utilisant le code non managé
Pour recevoir une notification des conflits de collision, une application effectue les actions suivantes avant de démarrer la synchronisation.
Elle implémente la méthode ISyncConstraintCallback::OnConstraintConflict et inscrit l'objet ISyncConstraintCallback en appelant ISyncSession::RegisterCallback.
Elle spécifie CCRP_NONE comme stratégie de résolution des conflits de collision à l'aide du mécanisme personnalisé fourni par le fournisseur de destination.
Si l'application a effectué ces étapes, l'applicateur de modifications appelle la méthode OnConstraintConflict une fois pour chaque conflit de contraintes de collision signalé pendant la synchronisation.
Étant donné qu'une stratégie de résolution de conflit ne peut pas être spécifiée pour les conflits de contraintes de non-collision, l'applicateur de modifications appelle également la méthode OnConstraintConflict une fois pour chaque conflit de contraintes de non-collision signalé.
La méthode OnConstraintConflict reçoit un objet IConstraintConflict qui contient des métadonnées et des données d'élément relatives aux deux modifications en conflit. La méthode peut examiner ces deux modifications, modifier des métadonnées ou des données d'élément et définir l'action de résolution du conflit à l'aide de la méthode IConstraintConflict::SetConstraintResolveActionForChange ou IConstraintConflict::GetConstraintResolveActionForChangeUnit. L'applicateur de modifications traite ensuite le conflit et distribue l'appel approprié à l'objet cible de l'applicateur de modifications. Gardez à l'esprit que les seules actions de résolution de conflit valides pour les conflits de contraintes de non-collision sont SCRA_TRANSFER_AND_DEFER et SCRA_DEFER.
Sync Framework fournit l'ensemble suivant d'actions de résolution de conflit de contraintes pour lesquelles l'applicateur de modifications gère la plupart du traitement.
Stratégie de résolution de conflit |
Description |
Type de conflit concerné |
---|---|---|
SCRA_ACCEPT_SOURCE_PROVIDER |
La modification effectuée sur le réplica source gagne toujours. L'applicateur de modifications passe la modification à la méthode ISynchronousNotifyingChangeApplierTarget::SaveChange et spécifie une action d'enregistrement SSA_DELETE_CONFLICTING_AND_SAVE_SOURCE_ITEM. La modification de la source est appliquée au réplica de destination et l'élément de destination en conflit est supprimé de ce dernier. |
Les conflits de collision uniquement. |
SCRA_ACCEPT_DESTINATION_PROVIDER |
La modification effectuée sur le réplica de destination gagne toujours. L'applicateur de modifications passe la modification de la source à la méthode SaveChange et spécifie une action d'enregistrement SSA_DELETE_AND_STORE_TOMBSTONE. Le fournisseur de destination crée un objet tombstone pour la modification de la source. Lorsque la destination joue le rôle de la source dans une synchronisation ultérieure, elle énumère une modification qui représente la suppression de l'élément source, et le supprime ainsi de la communauté de synchronisation. |
Les conflits de collision uniquement. |
SCRA_RENAME_SOURCE |
La modification envoyée du fournisseur de source est renommée afin qu'elle n'entre plus en conflit avec l'élément en conflit sur le réplica de destination, et la modification de la source est appliquée au réplica de destination. L'applicateur de modifications passe la modification à la méthode SaveChange et spécifie une action d'enregistrement SSA_RENAME_SOURCE_AND_UPDATE_VERSION_AND_DATA. |
Les conflits de collision uniquement. |
SCRA_RENAME_DESTINATION |
L'élément en conflit sur le réplica de destination est renommé afin qu'il n'entre plus en conflit avec la modification envoyée du fournisseur de source, et la modification de la source est appliquée au réplica de destination. L'applicateur de modifications passe la modification à la méthode SaveChange et spécifie une action d'enregistrement SSA_RENAME_DESTINATION_AND_UPDATE_VERSION_AND_DATA. |
Les conflits de collision uniquement. |
SCRA_MERGE |
Les données de l'élément source sont combinées à l'élément de destination. L'applicateur de modifications passe les données de modification du réplica source à la méthode SaveChange et spécifie une action d'enregistrement SSA_CHANGE_ID_UPDATE_VERSION_AND_MERGE_DATA. Pour plus d'informations, consultez Fusion des éléments en conflit, ci-dessous. |
Les conflits de collision uniquement. |
SCRA_TRANSFER_AND_DEFER |
Permet de consigner le conflit et de ne pas appliquer la modification. L'applicateur de modifications passe les données en conflit à la méthode ISynchronousNotifyingChangeApplierTarget2::SaveConstraintConflict, ce qui enregistre le conflit dans un journal des conflits. Pour plus d'informations sur la journalisation des conflits, consultez Journalisation et gestion des conflits. |
Tous les conflits de contraintes. |
SCRA_DEFER |
Permet d'ignorer le conflit et de ne pas appliquer la modification. L'applicateur de modifications ne passe pas les données en conflit au fournisseur de destination. |
Tous les conflits de contraintes. |
Fusion des éléments en conflit
La fusion de deux éléments d'un conflit de contraintes de collision diffère de la fusion des éléments d'un conflit d'accès concurrentiel, car les deux éléments qui font l'objet d'un conflit de collision ne possèdent pas les mêmes ID d'élément. Par exemple, un fichier nommé « FavoriteBooks.txt » est créé sur un réplica, et l'ID d'élément id1 lui est attribué. Un fichier nommé « FavoriteBooks.txt » est également créé sur un autre réplica, et l'ID d'élément id2 lui est attribué. Lorsque les réplicas sont synchronisés, Sync Framework traite ces deux éléments comme des éléments différents parce qu'ils n'ont pas les mêmes ID d'élément, alors que le réplica de destination les traite comme un même élément parce qu'ils portent le même nom. Ainsi, le fournisseur de destination signale un conflit de collision et spécifie que le contenu des deux éléments doit être fusionné. L'applicateur de modifications attribue l'ID id1 à l'élément fusionné et spécifie que le réplica de destination doit stocker un objet tombstone de fusion pour id2.
Lorsqu'un conflit de collision est résolu par la fusion, il est nécessaire de sélectionner l'un des ID d'élément comme l'ID d'élément gagnant qui est attribué à l'élément fusionné, et de vérifier que l'ID d'élément perdant a été fusionné. L'applicateur de modifications sélectionne l'ID d'élément gagnant en comparant les deux ID d'élément et sélectionnant le plus petit ID comme ID gagnant. L'ID d'élément gagnant est utilisé pour identifier l'élément fusionné sur le réplica de destination. Un objet tombstone de fusion est créé et stocké dans le réplica de destination. L'objet tombstone de fusion détecte que l'ID d'élément perdant identifie le même élément que l'ID d'élément gagnant dans la communauté de synchronisation. Les métadonnées d'un objet tombstone de fusion sont les mêmes que pour un objet tombstone d'élément supprimé, avec en plus l'ID d'élément gagnant.
Code managé Lorsque l'action de résolution de la modification est Merge, l'applicateur de modifications appelle SaveItemChange et spécifie une action d'enregistrement ChangeIdUpdateVersionAndMergeData. L'applicateur de modifications passe la modification avec l'ID d'élément perdant comme paramètre change. La modification avec l'ID d'élément gagnant peut être obtenue en appelant la méthode GetWinnerChange()()()() de l'objet SaveChangeContext passé dans le paramètre context.
Code non managé Lorsque l'action de résolution de la modification est SCRA_MERGE, l'applicateur de modifications appelle ISynchronousNotifyingChangeApplierTarget::SaveChange et spécifie une action d'enregistrement SSA_CHANGE_ID_UPDATE_VERSION_AND_MERGE_DATA. L'applicateur de modifications passe la modification avec l'ID d'élément perdant comme paramètre pChange. La modification avec l'ID d'élément gagnant peut être obtenue en appelant la méthode ISaveChangeContext2::GetWinnerChange de l'objet ISaveChangeContext2 passé dans le paramètre pSaveContext.
Le fournisseur de destination doit effectuer plusieurs étapes pour traiter l'action de fusion de manière appropriée. Prenons l'exemple d'une action de fusion qui spécifie id1 comme ID d'élément perdant et id2 comme ID d'élément gagnant. Le fournisseur de destination doit effectuer les étapes suivantes dans une seule transaction.
Stocker un objet tombstone de fusion dans les métadonnées de destination. L'objet tombstone de fusion contient id1 comme ID d'élément perdant et id2 comme ID d'élément gagnant. Si un objet tombstone de fusion existe déjà dans le réplica de destination qui contient id1 comme ID d'élément perdant et un autre ID d'élément, id3, comme ID d'élément gagnant, le fournisseur effectue les étapes suivantes.
Si id2 est supérieur à id3, le fournisseur crée et stocke deux objets tombstone de fusion. Un objet tombstone de fusion contient id1 comme ID d'élément perdant et id2 comme ID d'élément gagnant. L'autre objet tombstone de fusion contient id2 comme ID d'élément perdant et id3 comme ID d'élément gagnant. Il est possible que ce deuxième objet tombstone de fusion existe déjà, auquel cas il est simplement conservé inchangé. Ainsi, une chaîne d'objets tombstone de fusion est créée, classée par ID d'élément décroissant.
Si id3 est supérieur à id2, le fournisseur retourne une erreur.
Fusionner les données pour l'élément du réplica de destination avec les données pour l'élément du fournisseur de source. L'élément de destination peut être identifié par id1 ou id2.
Appliquer les métadonnées de modification aux métadonnées de destination et les données de modification fusionnée au magasin d'éléments de destination, en utilisant l'ID d'élément gagnant id2 comme ID d'élément pour la modification fusionnée. Les métadonnées de modification peuvent être obtenues en appelant la méthode GetWinnerChange()()()() de context (pour le code managé) ou la méthode GetWinnerChange de pContext (pour le code non managé).
Propagation d'un élément fusionné
La propagation des éléments fusionnés d'un conflit de contraintes de collision diffère de la propagation des éléments fusionnés d'un conflit d'accès concurrentiel, car les conflits peuvent se produire avec l'ID d'élément gagnant, l'ID d'élément perdant, ou les deux à la fois. Par exemple, le réplica X contient un élément avec l'ID id1 qui a été fusionné à partir d'éléments possédant les ID id1 et id2. Le réplica Y contient un élément avec l'ID id2, auquel il a apporté des modifications locales. Lorsque l'élément fusionné identifié par l'ID id1 est envoyé au réplica Y par le réplica X, un conflit se produit, car id1 fait maintenant référence au même élément identifié par id2.
L'applicateur de modifications aide le fournisseur de destination à appliquer une modification d'élément fusionné en détectant les conflits d'accès concurrentiel qui se produisent à la fois avec l'ID d'élément gagnant et l'ID d'élément perdant, et en déterminant l'action appropriée que le fournisseur de destination doit prendre pour appliquer la modification d'élément fusionné au réplica de destination. Si le fournisseur de destination détecte un conflit de contraintes lorsqu'il applique une modification d'élément fusionné, il doit le signaler comme tout autre conflit de contraintes.
L'applicateur de modifications détecte également les situations où le réplica source et le réplica de destination sont en désaccord sur l'identité d'un élément. Par exemple, le réplica X résout un conflit de collision entre des éléments ayant les ID id1 et id2 en fusionnant les éléments et en attribuant l'ID id1 à l'élément fusionné. Le réplica Y résout un conflit de collision entre des éléments ayant les ID id1 et id2 en renommant l'élément identifié par id1 et en conservant les deux éléments. Le réplica X envoie l'élément fusionné identifié par id1 et un objet tombstone de fusion qui indique que id2 a été fusionné dans id1. Le conflit sur id1 est détecté et résolu en tant que conflit d'accès concurrentiel. Le conflit sur id2 est détecté et signalé à l'application de synchronisation en tant que conflit d'identité en spécifiant Identity (pour le code managé) ou CCR_IDENTITY (pour le code non managé) comme raison du conflit. L'application détermine s'il faut résoudre le conflit en conservant la modification de la source ou la modification de destination.
N'oubliez pas que, lorsque le fournisseur de source utilise le filtrage d'unité de modification et que le fournisseur de destination n'est pas filtré, un conflit d'identité peut parfois se produire même quand l'élément identifié par l'objet tombstone de fusion est sur le point d'être supprimé du réplica de destination. Ce conflit est du à la façon dont la connaissance filtrée est gérée par l'applicateur de modifications. Pour garantir la synchronisation et la propagation appropriée de l'objet tombstone de fusion, le fournisseur de destination doit conserver l'objet tombstone de fusion et supprimer l'élément en conflit du réplica de destination.
Lorsqu'une modification d'élément fusionné est envoyée par le fournisseur de source, l'applicateur de modifications détermine l'action appropriée que le fournisseur de destination doit prendre pour appliquer la modification au réplica de destination. Le tableau suivant répertorie les actions d'enregistrement que l'applicateur de modifications peut spécifier, ainsi que les actions que le fournisseur doit prendre pour appliquer la modification.
Action d'enregistrement |
Actions du fournisseur |
---|---|
ChangeIdUpdateVersionAndSaveData (pour le code managé), SSA_CHANGE_ID_UPDATE_VERSION_AND_SAVE_DATA (pour le code non managé) |
Stocker un objet tombstone de fusion pour l'ID d'élément perdant, en suivant les mêmes étapes que celles présentées dans Fusion des éléments en conflit, ci-dessus. Appliquer la modification d'élément gagnant. |
ChangeIdUpdateVersionOnly (pour le code managé), SSA_CHANGE_ID_UPDATE_VERSION_ONLY (pour le code non managé) |
Stocker un objet tombstone de fusion pour l'ID d'élément perdant, en suivant les mêmes étapes que celles présentées dans Fusion des éléments en conflit, ci-dessus. Appliquer uniquement des métadonnées pour la modification d'élément gagnant. |
ChangeIdUpdateVersionAndDeleteAndStoreTombstone (pour le code managé), SSA_CHANGE_ID_UPDATE_VERSION_AND_DELETE_AND_STORE_TOMBSTONE (pour le code non managé) |
Stocker un objet tombstone de fusion pour l'ID d'élément perdant, en suivant les mêmes étapes que celles présentées dans Fusion des éléments en conflit, ci-dessus. Supprimer l'élément identifié par l'ID d'élément gagnant, puis stocker un objet tombstone pour lui. |
StoreMergeTombstone (pour le code managé), SSA_STORE_MERGE_TOMBSTONE (pour le code non managé) |
Stocker un objet tombstone de fusion pour l'ID d'élément perdant, en suivant les mêmes étapes que celles présentées dans Fusion des éléments en conflit, ci-dessus. |
Notes
Toutes les étapes d'une action d'enregistrement doivent être appliquées comme une action atomique.
Voir aussi
Référence
SaveChangeWithChangeUnitsContext
INotifyingChangeApplierTarget2
Autres ressources
Détection et résolution des conflits d'accès concurrentiel
Interface ISaveChangeWithChangeUnitsContext2