制約の競合の検出および解決
制約の競合は、項目が持つ制約 (フォルダーの関係や、ファイル システムにおいて、まったく同じ名前が付けられたデータの場所など) に違反する競合です。Sync Framework には、制約の競合の解決を容易にする変更適用元オブジェクトが用意されています。
制約の競合は、同期の変更適用フェーズ中に同期先プロバイダーによって検出されます。制約の競合を検出した同期先プロバイダーは、競合を変更適用元に報告します。セッションに対して設定されている競合の解決方法か、指定された競合に対してアプリケーションが設定した競合解決アクションに従って、変更適用元が競合を解決します。その後、変更適用元は、同期先プロバイダーが解決された競合を同期先レプリカに適用できるように、必要な同期先プロバイダーの呼び出しをディスパッチします。
プロバイダーは、制約の競合を報告して変更適用元を使用する際に、競合ログを提供する必要もあります。変更適用元は、この競合ログを使用して競合を処理およびログ記録します。Sync Framework は、独自の競合ログを実装しないプロバイダー向けに、競合ログのメモリ内実装を提供します。詳細については、「競合のログ記録と管理」を参照してください。
カスタム フィルターや変更適用サービスを利用するプロバイダーでは制約の競合を使用できないことに注意してください。このようなプロバイダーで制約の競合を使用すると、予期しない結果が生じる可能性があります。
制約の競合の種類
制約の競合は、同期先レプリカが使用しているデータ ストアに応じて、さまざまな形で生じます。制約の競合は、Sync Framework では次の 3 種類に分けられます。
衝突競合: 同期元プロバイダーが同期先レプリカに既に存在するファイルと同じ名前および場所のファイルを送信する場合など、同期先のストアにある別の項目との競合が原因で項目を保存できない場合に発生します。
親の欠落に起因する競合: 必要な親項目が階層型のデータ ストアに存在せず、項目をストアに保存できない場合に発生します。同期先レプリカには存在しないディレクトリを保存先とするファイルが同期元プロバイダーから送信された場合などが該当します。
その他の制約の競合: 保存しようとしている項目が、同期先レプリカの制約に違反している場合に発生します。同期元プロバイダーから送信されたファイルが大きすぎて同期先レプリカに保存できない場合や、変更が同期先レプリカのビジネス ロジックに違反する場合などが該当します。ビジネス ロジックの競合の例として、name および country という 2 つの変更単位が格納されている、忠実性の低いレプリカを考えてみます。また、name、state/province、および country という 3 つの変更単位が格納されている、忠実性の高いレプリカについても考えてみます。忠実性の高いレプリカには、state/province フィールドを country フィールドと照合するビジネス ロジックが含まれており、この照合に合格しない変更は格納されません。忠実性の低いレプリカは、同期元として機能し、country が "USA" に設定された項目を送信します。同期先プロバイダーは、忠実性の高いレプリカに変更の適用を試みますが、忠実性の高いレプリカでは、項目の state/province フィールドに "British Columbia" が含まれています。そのため、この変更はビジネス ロジックに違反し、制約の競合が発生します。
同期先プロバイダーは、次のいずれかの値を選択して、制約の競合の理由を指定します。
制約の競合の理由 | 説明 |
---|---|
Collision (マネージ コードの場合)、CCR_COLLISION (アンマネージ コードの場合) |
項目がストア内の別の項目 (既存の項目と同じ名前の項目など) と競合しているので、項目を保存できません。プロバイダーでは、同期先項目の ID を競合する項目 ID として指定する必要があります。 |
NoParent (マネージ コードの場合)、CCR_NOPARENT (アンマネージ コードの場合) |
階層データ ストアに存在しない親項目が項目に必要なので、項目をストアに保存できません。プロバイダーでは、必要に応じて、存在しない親項目の ID を競合する項目 ID として指定できます。 |
Other (マネージ コードの場合)、CCR_OTHER (アンマネージ コードの場合) |
項目または変更単位が、同期先レプリカの他の制約に違反しています。プロバイダーでは、必要に応じて、競合する項目の ID を競合する項目 ID として指定できます。 |
制約の競合の検出および報告
制約の競合の検出は、レプリカで使用されているデータ ストアに依存します。したがって、同期先プロバイダーで制約の競合を検出する必要があります。たとえば、階層構造を持ったファイル システムを表すプロバイダーは、保存データに適用される、ストア固有の制約 (場所、名前、サイズなど) を検出できなければなりません。
制約の競合は、同期の変更適用フェーズ中に同期先プロバイダーによって検出されます。
マネージ コード 制約の競合は、通常は同期先プロバイダーの SaveItemChange メソッドまたは SaveChangeWithChangeUnits メソッドによって検出され、RecordConstraintConflictForItem または RecordConstraintConflictForChangeUnit を呼び出すことで報告されます。
アンマネージ コード 制約の競合は、通常は同期先プロバイダーの ISynchronousNotifyingChangeApplierTarget::SaveChange メソッドまたは ISynchronousNotifyingChangeApplierTarget::SaveChangeWithChangeUnits メソッドによって検出され、ISaveChangeContext2::SetConstraintConflictOnChange または ISaveChangeWithChangeUnitsContext2::SetConstraintConflictOnChangeUnit を呼び出すことで報告されます。
変更適用元は、制約の競合の報告を受け取ると、いくつかの処理を行います。
制約の競合が衝突競合である場合、競合適用元は、その競合が新しい競合、一時的な競合、マージによる解決の反映のいずれであるかを特定します。競合の処理中に、変更適用元は、SaveConstraintConflict (マネージ コードの場合) または ISynchronousNotifyingChangeApplierTarget2::SaveConstraintConflict (アンマネージ コードの場合) を呼び出して、競合を競合ログに一時的に保存することがあります。変更適用元は、同期セッションの終了時にログから一時的な競合を削除します。
セッションに対して設定されている衝突競合の解決方法か、アプリケーションが決定した競合解決アクションに従って、衝突競合を解決します。衝突競合の解決方法が ApplicationDefined (マネージ コードの場合) または CCRP_NONE (アンマネージ コードの場合) に設定されている場合は、競合解決アクションを決定するためにアプリケーションが呼び出されます。
アプリケーションが決定した競合解決アクションに従って、衝突以外の制約の競合を解決します。衝突以外の制約の競合に対して競合の解決方法を設定することはできません。
制約の競合の解決
同期先プロバイダーは、制約の競合を解決するために変更適用元を使用します。その際、変更適用元は、プロバイダーが指定した変更適用元の対象オブジェクトの呼び出しをディスパッチします。衝突競合の解決方法が指定されている場合、変更適用元はそれを基に、発生した各衝突競合を解決するのに必要な競合解決アクションを決定します。カスタムの衝突競合の解決方法が指定されている場合、変更適用元は同期アプリケーションに衝突競合を通知し、アプリケーションが競合解決アクションを指定します。競合の解決方法は衝突以外の制約の競合には指定できないため、衝突以外の制約の競合が報告された場合、変更適用元は、アプリケーションが競合解決アクションを指定できるように、毎回アプリケーションに競合を通知します。どの場合でも、変更適用元が適切な変更適用元の対象メソッドを呼び出し、変更適用元の対象オブジェクトが処理 (レプリカへの変更の保存や、後の処理に備えた競合のログ記録など) を行います。
衝突競合の解決方法の指定
同期アプリケーションは、通常は同期の開始前に衝突競合の解決方法を指定します。
マネージ コード アプリケーションは、同期先プロバイダーの CollisionConflictResolutionPolicy プロパティを目的の値に設定することで、解決方法を指定します。
アンマネージ コード アプリケーションは、カスタム メカニズム (アプリケーションが同期先プロバイダー オブジェクトで QueryInterface を呼び出して取得したカスタム インターフェイスなど) を使用して解決方法を指定します。
変更適用元が変更適用元のターゲットにメソッドを適切にディスパッチできるように、同期先プロバイダーは、変更適用元の ApplyChanges メソッド (マネージ コードの場合) または ISynchronousNotifyingChangeApplier2::ApplyChanges メソッド (アンマネージ コードの場合) に衝突競合の解決方法を渡します。変更適用元のターゲットは、INotifyingChangeApplierTarget2 オブジェクト (マネージ コードの場合) または ISynchronousNotifyingChangeApplierTarget2 オブジェクト (アンマネージ コードの場合) によって表されます。
マネージ コード向けの衝突競合の解決方法
Sync Framework では、マネージ コード向けに、次の衝突競合の解決方法が定義されています。
競合の解決方法 | 説明 |
---|---|
同期元レプリカで行われた変更が常に優先されます。Sync Framework によって、SourceWins の競合解決アクションが指定されます。 |
|
同期先レプリカで行われた変更が常に優先されます。Sync Framework によって、DestinationWins の競合解決アクションが指定されます。 |
|
同期元プロバイダーから送信された変更は、同期先レプリカで競合する項目と競合することがないように名前が変更されます。また、同期元の変更は同期先レプリカに適用されます。Sync Framework によって、RenameSource の競合解決アクションが指定されます。 |
|
同期先レプリカで競合している項目は、同期元プロバイダーから送信された変更と競合しないように名前が変更されます。また、同期元の変更が同期先レプリカに適用されます。Sync Framework によって、RenameDestination の競合解決アクションが指定されます。 |
|
同期元項目のデータが同期先項目に結合されます。Sync Framework によって、Merge の競合解決アクションが指定されます。 |
|
変更適用元が ItemConstraint イベントを使用して、各衝突競合が発生したときに同期アプリケーションに通知します。アプリケーションでは、競合している項目を調べ、SetResolutionAction を呼び出して競合解決アクションを指定します。 |
アンマネージ コード向けの衝突競合の解決方法
Sync Framework では、アンマネージ コード向けに、次の衝突競合の解決方法が定義されています。
競合の解決方法 | 説明 |
---|---|
CCRP_SOURCE_PROVIDER_WINS |
同期元レプリカで行われた変更が常に優先されます。Sync Framework によって、SCRA_ACCEPT_SOURCE_PROVIDER の競合解決アクションが指定されます。 |
CCRP_DESTINATION_PROVIDER_WINS |
同期先レプリカで行われた変更が常に優先されます。Sync Framework によって、SCRA_ACCEPT_DESTINATION_PROVIDER の競合解決アクションが指定されます。 |
CCRP_RENAME_SOURCE |
同期元プロバイダーから送信された変更は、同期先レプリカで競合する項目と競合することがないように名前が変更されます。また、同期元の変更は同期先レプリカに適用されます。Sync Framework によって、SCRA_RENAME_SOURCE の競合解決アクションが指定されます。 |
CCRP_RENAME_DESTINATION |
同期先レプリカで競合している項目は、同期元プロバイダーから送信された変更と競合しないように名前が変更されます。また、同期元の変更が同期先レプリカに適用されます。Sync Framework によって、SCRA_RENAME_DESTINATION の競合解決アクションが指定されます。 |
CCRP_MERGE |
同期元項目のデータが同期先項目に結合されます。Sync Framework によって、SCRA_MERGE の競合解決アクションが指定されます。 |
CCRP_NONE |
変更適用元が ISyncConstraintCallback::OnConstraintConflict イベントを使用して、各衝突競合が発生したときに同期アプリケーションに通知します。アプリケーションでは、競合している項目を調べ、IConstraintConflict::SetConstraintResolveActionForChange または IConstraintConflict::GetConstraintResolveActionForChangeUnit を呼び出して競合解決アクションを指定します。 |
カスタム競合解決の指定
アプリケーションは、制約の競合が発生するたびに競合解決アクションを指定することを示すことができます。そのために、アプリケーションは制約の競合の通知を受け取るための登録を行います。制約の競合が報告されると、Sync Framework がアプリケーションに通知を行います。その後で、アプリケーションは競合を分析し、目的の競合解決アクションを設定できます。
マネージ コードでのカスタム競合解決の指定
衝突競合の通知を受け取るために、アプリケーションは同期の開始前に次の操作を実行します。
同期先プロバイダーの ItemConstraint イベントのイベント ハンドラーを登録します。
同期先プロバイダーの CollisionConflictResolutionPolicy プロパティを ApplicationDefined に設定します。
アプリケーションでこれらの手順が完了している場合、変更適用元は、同期中に報告された衝突の制約の競合ごとに 1 回だけ ItemConstraint イベントを生成します。
競合の解決方法は衝突以外の制約の競合には指定できないため、変更適用元は、報告された衝突以外の制約の競合ごとに 1 回だけ ItemConstraint イベントも生成します。
ItemConstraint イベントのイベント ハンドラーには、競合する 2 つの変更のメタデータおよび項目データを保持する ItemConstraintEventArgs オブジェクトが渡されます。このイベント ハンドラーでは、競合する 2 つの変更を調査して、メタデータまたは項目データに変更を加え、さらに SetResolutionAction メソッドを使用して、競合の解決アクションを設定できます。その後、変更適用元が競合を処理し、変更適用元の対象オブジェクトに適切な呼び出しをディスパッチします。ただし、制約の競合が衝突競合ではない場合、有効な競合解決アクションは SaveConflict と SkipChange だけです。
Sync Framework には制約の競合に対する一連の解決アクションが用意されており、変更適用元はそれらを利用することで、解決処理の大半を実行できます。
競合解決アクション | 説明 | アクションが有効な競合の種類 |
---|---|---|
SourceWins |
同期元レプリカで行われた変更が優先されます。変更適用元は、変更を SaveItemChange メソッドに渡し、DeleteConflictingAndSaveSourceItem の保存操作を指定します。同期元の変更が同期先レプリカに適用され、競合する同期先の項目は同期先レプリカから削除されます。 |
衝突競合のみ。 |
DestinationWins |
同期先レプリカで行われた変更が優先されます。変更適用元は、同期元の変更を SaveItemChange メソッドに渡し、DeleteAndStoreTombstone の保存操作を指定します。同期先プロバイダーは、同期元の変更の廃棄標識を作成します。同期先は、その後の同期で同期元となったとき、同期元項目の削除につながる変更を列挙します。その結果、その項目が同期コミュニティから削除されます。 |
衝突競合のみ。 |
RenameSource |
同期元プロバイダーから送信された変更は、同期先レプリカの競合する項目と以降の競合を避けるために名前が変更され、同期先レプリカに適用されます。変更適用元は、変更を SaveItemChange メソッドに渡し、RenameSourceAndUpdateVersionAndData の保存操作を指定します。 |
衝突競合のみ。 |
RenameDestination |
同期先レプリカの競合している項目は、同期元プロバイダーから送信された変更と以降の競合を避けるために名前が変更され、同期元プロバイダーから送信された変更が同期先レプリカに適用されます。変更適用元は、変更を SaveItemChange メソッドに渡し、RenameDestinationAndUpdateVersionData の保存操作を指定します。 |
衝突競合のみ。 |
Merge |
同期元項目のデータが同期先項目と結合されます。変更適用元は、同期元レプリカの変更データを SaveItemChange メソッドに渡し、ChangeIdUpdateVersionAndMergeData の保存操作を指定します。詳細については、以降の「競合している項目のマージ」を参照してください。 |
衝突競合のみ。 |
SaveConflict |
競合をログに記録します。変更は適用されません。変更適用元は、競合データを SaveConstraintConflict メソッドに渡します。これにより、競合ログに競合が保存されます。競合のログ記録の詳細については、「競合のログ記録と管理」を参照してください。 |
すべての制約の競合。 |
SkipChange |
競合を無視します。変更は適用されません。変更適用元は、競合データを同期先プロバイダーに渡しません。 |
すべての制約の競合。 |
アンマネージ コードでのカスタム競合解決の指定
衝突競合の通知を受け取るために、アプリケーションは同期の開始前に次の操作を実行します。
ISyncConstraintCallback::OnConstraintConflict メソッドを実装し、ISyncSession::RegisterCallback を呼び出して ISyncConstraintCallback オブジェクトを登録します。
同期先プロバイダーのカスタム メカニズムを使用し、衝突競合の解決方法として CCRP_NONE を指定します。
アプリケーションでこれらの手順が完了している場合、変更適用元は、同期中に報告された衝突の制約の競合ごとに 1 回だけ OnConstraintConflict メソッドを呼び出します。
競合の解決方法は衝突以外の制約の競合には指定できないため、変更適用元は、報告された衝突以外の制約の競合ごとに 1 回だけ OnConstraintConflict メソッドも呼び出します。
OnConstraintConflict メソッドには、競合する 2 つの変更のメタデータおよび項目データを保持する IConstraintConflict オブジェクトが渡されます。このメソッドでは、競合する 2 つの変更を調査して、メタデータまたは項目データに変更を加え、さらに IConstraintConflict::SetConstraintResolveActionForChange メソッドまたは IConstraintConflict::GetConstraintResolveActionForChangeUnit メソッドを使用して、競合の解決アクションを設定できます。その後、変更適用元が競合を処理し、変更適用元の対象オブジェクトに適切な呼び出しをディスパッチします。ただし、制約の競合が衝突競合ではない場合、有効な競合解決アクションは SCRA_TRANSFER_AND_DEFER と SCRA_DEFER だけです。
Sync Framework には制約の競合に対する一連の解決アクションが用意されており、変更適用元はそれらを利用することで、解決処理の大半を実行できます。
競合の解決方法 | 説明 | アクションが有効な競合の種類 |
---|---|---|
SCRA_ACCEPT_SOURCE_PROVIDER |
同期元レプリカで行われた変更が常に優先されます。変更適用元は、変更を ISynchronousNotifyingChangeApplierTarget::SaveChange メソッドに渡し、SSA_DELETE_CONFLICTING_AND_SAVE_SOURCE_ITEM の保存操作を指定します。同期元の変更が同期先レプリカに適用され、競合する同期先の項目は同期先レプリカから削除されます。 |
衝突競合のみ。 |
SCRA_ACCEPT_DESTINATION_PROVIDER |
同期先レプリカで行われた変更が常に優先されます。変更適用元は、同期元の変更を SaveChange メソッドに渡し、SSA_DELETE_AND_STORE_TOMBSTONE の保存操作を指定します。同期先プロバイダーは、同期元の変更の廃棄標識を作成します。同期先は、その後の同期で同期元となったとき、同期元項目の削除につながる変更を列挙します。その結果、その項目が同期コミュニティから削除されます。 |
衝突競合のみ。 |
SCRA_RENAME_SOURCE |
同期元プロバイダーから送信された変更は、同期先レプリカの競合する項目と以降の競合を避けるために名前が変更され、同期先レプリカに適用されます。変更適用元は、変更を SaveChange メソッドに渡し、SSA_RENAME_SOURCE_AND_UPDATE_VERSION_AND_DATA の保存操作を指定します。 |
衝突競合のみ。 |
SCRA_RENAME_DESTINATION |
同期先レプリカの競合している項目は、同期元プロバイダーから送信された変更と以降の競合を避けるために名前が変更され、同期元プロバイダーから送信された変更が同期先レプリカに適用されます。変更適用元は、変更を SaveChange メソッドに渡し、SSA_RENAME_DESTINATION_AND_UPDATE_VERSION_AND_DATA の保存操作を指定します。 |
衝突競合のみ。 |
SCRA_MERGE |
同期元項目のデータが同期先項目と結合されます。変更適用元は、同期元レプリカの変更データを SaveChange メソッドに渡し、SSA_CHANGE_ID_UPDATE_VERSION_AND_MERGE_DATA の保存操作を指定します。詳細については、以降の「競合している項目のマージ」を参照してください。 |
衝突競合のみ。 |
SCRA_TRANSFER_AND_DEFER |
競合をログに記録します。変更は適用されません。変更適用元は、競合データを ISynchronousNotifyingChangeApplierTarget2::SaveConstraintConflict メソッドに渡します。これにより、競合ログに競合が保存されます。競合のログ記録の詳細については、「競合のログ記録と管理」を参照してください。 |
すべての制約の競合。 |
SCRA_DEFER |
競合を無視します。変更は適用されません。変更適用元は、競合データを同期先プロバイダーに渡しません。 |
すべての制約の競合。 |
競合している項目のマージ
衝突の制約の競合が生じている 2 つの項目をマージする場合、衝突競合に関係する 2 つの項目は項目 ID が異なるため、同時実行の競合が生じている項目のマージとは異なる方法で処理されます。たとえば、"FavoriteBooks.txt" という名前のファイルがレプリカで作成され、項目 ID id1 が付与されたとします。また、同じ "FavoriteBooks.txt" という名前のファイルが別のレプリカで作成され、項目 ID id2 が付与されたとします。レプリカの同期時に、Sync Framework はこれらの 2 つの項目を別の項目として扱いますが (項目 ID が異なるため)、同期先レプリカはこれらを同じ項目として扱います (名前が同じであるため)。したがって、同期先プロバイダーは衝突競合を報告し、2 つの項目のコンテンツをマージするように指定します。変更適用元は、マージされた項目に ID id1 を割り当て、同期先レプリカに id2 のマージ廃棄標識を格納するように指定します。
マージによって衝突競合を解決する場合は、優先される項目 ID としていずれかの項目 ID を選択し、それをマージされた項目に割り当てると同時に、優先されない項目 ID がマージされたことを適切に追跡する必要があります。変更適用元は、2 つの項目 ID を比較し、小さい方の ID を優先される項目 ID として選択します。優先される項目 ID は、マージされた項目を同期先レプリカで識別するために使用されます。**"マージ廃棄標識" は、同期先レプリカで作成、格納されます。マージ廃棄標識は、優先されない項目 ID が同期コミュニティ内の優先される項目 ID と同じ項目を示すことを追跡します。マージ廃棄標識のメタデータは、削除された項目の廃棄標識のメタデータと同じですが、優先される項目 ID が付加されています。
マネージ コード 変更の解決アクションが Merge であるとき、変更適用元は、SaveItemChange を呼び出し、ChangeIdUpdateVersionAndMergeData の保存操作を指定します。変更適用元は、優先されない項目 ID を持つ変更を change パラメーターとして渡します。優先される項目 ID を持つ変更は、context パラメーターで渡される SaveChangeContext オブジェクトの GetWinnerChange メソッドを呼び出すことで取得できます。
アンマネージ コード 変更の解決アクションが SCRA_MERGE であるとき、変更適用元は、ISynchronousNotifyingChangeApplierTarget::SaveChange を呼び出し、SSA_CHANGE_ID_UPDATE_VERSION_AND_MERGE_DATA の保存操作を指定します。変更適用元は、優先されない項目 ID を持つ変更を pChange パラメーターとして渡します。優先される項目 ID を持つ変更は、pSaveContext パラメーターで渡される ISaveChangeContext2 オブジェクトの ISaveChangeContext2::GetWinnerChange メソッドを呼び出すことで取得できます。
同期先プロバイダーは、マージ アクションを適切に処理するために、いくつかの手順を実行する必要があります。優先されない項目 ID として id1、優先される項目 ID として id2 を指定するマージ アクションを考えてみます。同期先プロバイダーは、1 つのトランザクションで次の手順を実行する必要があります。
マージ廃棄標識を同期先メタデータに格納します。マージ廃棄標識には、優先されない項目 ID として id1、優先される項目 ID として id2 が含まれます。優先されない項目 ID として id1 を含み、さらに、優先される項目 ID として別の項目 ID id3 を含む同期先レプリカにマージ廃棄標識が既に存在する場合、プロバイダーは次の手順を実行します。
id2 が id3 より大きい場合、プロバイダーは 2 つのマージ廃棄標識を作成して格納します。一方のマージ廃棄標識には、優先されない項目 ID として id1、優先される項目 ID として id2 が含まれます。もう一方のマージ廃棄標識には、優先されない項目 ID として id2、優先される項目 ID として id3 が含まれます。この 2 つ目のマージ廃棄標識は既に存在する可能性があります。この場合、このマージ廃棄標識はそのまま残るだけです。このようにして、一連のマージ廃棄標識が作成され、項目 ID で降順で順序付けられます。
id3 が id2 より大きい場合、プロバイダーはエラーを返します。
同期先レプリカの項目のデータを同期元プロバイダーの項目のデータとマージします。同期先項目は、id1 または id2 で識別されます。
優先される項目 ID id2 をマージされた変更の項目 ID として使用して、変更のメタデータを同期先メタデータに適用し、変更のマージされたデータを同期先項目ストアに適用します。変更のメタデータを取得するには、context の GetWinnerChange メソッド (マネージ コードの場合) か、pContext の GetWinnerChange メソッド (アンマネージ コードの場合) を呼び出します。
マージされた項目の反映
衝突の制約の競合によってマージされた項目の反映は、同時実行の競合によってマージされた項目の反映とは異なる処理です。優先される項目 ID と優先されない ID のどちらか一方、または両方で競合が発生する可能性があるためです。たとえば、レプリカ X には、ID が id1 の項目と id2 の項目がマージされた、ID が id1 の項目が含まれるとします。レプリカ Y には、ID が id2 の項目が含まれ、その項目にはローカルの変更が加えられています。id1 で識別されるマージされた項目がレプリカ X からレプリカ Y に送信されると、id1 は id2 と同じ項目を参照することになるため、競合が発生します。
同期先プロバイダーは、変更適用元を使用して、マージされた項目の変更を適用します。その際、変更適用元は、優先される項目 ID と優先されない項目 ID の両方で発生する同時実行の競合を検出します。また、マージされた項目の変更を同期先レプリカに適用するために、同期先プロバイダーが実行する必要のある適切なアクションを決定します。同期先プロバイダーがマージされた項目の変更を適用する際に、制約の競合を検出した場合は、他の制約の競合の場合と同じように報告する必要があります。
変更適用元は、同期元レプリカと同期先レプリカで項目 ID の処理方法が異なる場合にも、それを検出します。たとえば、レプリカ X では、id1 および id2 という ID の項目間の衝突競合を解決するために、項目をマージして、マージされた項目に id1 を割り当てます。レプリカ Y では、id1 および id2 という ID の項目間の衝突競合を解決するために、id1 で示される項目の名前を変更して、両方の項目を保持します。レプリカ X は、id1 で示されるマージされた項目と、id2 が id1 にマージされたことを示すマージ廃棄標識を送信します。id1 での競合が検出され、同時実行の競合として解決されます。Identity (マネージ コードの場合) または CCR_IDENTITY (アンマネージ コードの場合) の競合理由を指定すると、id2 で発生している競合が検出され、ID の競合として同期アプリケーションに報告されます。このアプリケーションによって、同期元の変更と同期先の変更のどちらを保持して競合を解決するかが決定されます。
同期元プロバイダーが変更単位フィルターを使用していて、同期先プロバイダーにフィルターが適用されていないと、マージ廃棄標識で識別される項目を同期先レプリカから削除する場合にも ID の競合が発生することがあります。これは、フィルター選択されたナレッジが変更適用元によって処理される方法に関係しています。マージ廃棄標識の同期と反映が正しく行われるようにするには、同期先プロバイダーでマージ廃棄標識を保持して、競合する項目を同期先レプリカから削除する必要があります。
同期元プロバイダーがマージされた項目の変更を送信すると、変更適用元は、同期先プロバイダーが変更を同期先レプリカに適用するために実行する必要のあるアクションを決定します。次の表に、変更適用元が指定できる保存操作と、プロバイダーが変更を適用するために実行する必要のあるアクションを示します。
保存操作 | プロバイダーによるアクション |
---|---|
ChangeIdUpdateVersionAndSaveData (マネージ コードの場合)、SSA_CHANGE_ID_UPDATE_VERSION_AND_SAVE_DATA (アンマネージ コードの場合) |
前の「競合している項目のマージ」で説明した手順に従って、優先されない項目 ID のマージ廃棄標識を格納します。優先される項目の変更を適用します。 |
ChangeIdUpdateVersionOnly (マネージ コードの場合)、SSA_CHANGE_ID_UPDATE_VERSION_ONLY (アンマネージ コードの場合) |
前の「競合している項目のマージ」で説明した手順に従って、優先されない項目 ID のマージ廃棄標識を格納します。優先される項目の変更のメタデータのみを適用します。 |
ChangeIdUpdateVersionAndDeleteAndStoreTombstone (マネージ コードの場合)、SSA_CHANGE_ID_UPDATE_VERSION_AND_DELETE_AND_STORE_TOMBSTONE (アンマネージ コードの場合) |
前の「競合している項目のマージ」で説明した手順に従って、優先されない項目 ID のマージ廃棄標識を格納します。優先される項目 ID によって識別された項目を削除し、その廃棄標識を格納します。 |
StoreMergeTombstone (マネージ コードの場合)、SSA_STORE_MERGE_TOMBSTONE (アンマネージ コードの場合) |
前の「競合している項目のマージ」で説明した手順に従って、優先されない項目 ID のマージ廃棄標識を格納します。 |
注意
保存操作のすべての手順は、アトミックな操作として適用される必要があります。
参照
リファレンス
ISaveChangeContext2 インターフェイス
ISaveChangeWithChangeUnitsContext2 インターフェイス
ISynchronousNotifyingChangeApplier2 インターフェイス
ISynchronousNotifyingChangeApplierTarget2 インターフェイス
SaveChangeContext
SaveChangeWithChangeUnitsContext
NotifyingChangeApplier
INotifyingChangeApplierTarget2