단순 공급자의 충돌 처리
응용 프로그램은 가능한 한 충돌을 방지하도록 디자인되어야 합니다. 충돌을 검색하고 해결하려면 보다 정교한 기술과 처리 능력이 필요하고 네트워크 트래픽이 증가합니다. 일부 응용 프로그램에서는 충돌이 불가피하게 발생합니다. 예를 들어 영업 응용 프로그램에서 두 영업 사원이 지역을 공유할 수 있으며 동일한 고객과 주문에 대한 데이터를 업데이트할 수 있습니다. 동기화 커뮤니티에서 항목에 대한 변경 내용이 올바로 전파되도록 하려면 원본 공급자에서 받은 항목과 대상 복제본의 항목 간에 발생하는 충돌을 대상 공급자에서 검색하고 처리해야 합니다. Sync Framework에서는 충돌을 검색하고 처리하는 데 필요한 대부분의 작업을 수행하는 개체를 제공합니다.
Sync Framework에서는 충돌을 항목 또는 변경 단위 수준에서 검색합니다. Sync Framework에서는 동기화 중에 발생할 수 있는 두 가지 충돌 범주인 동시성 충돌과 제약 조건 충돌을 인식합니다. 나중에 동기화되는 서로 다른 두 복제본에서 같은 항목 또는 변경 단위가 변경될 경우 동시성 충돌이 발생합니다. 제약 조건 충돌은 항목 또는 변경 단위에 적용되는 제약 조건(예: 파일 시스템 내에서 폴더의 관계 또는 이름이 같은 데이터의 위치 등)을 위반하는 충돌입니다. Sync Framework에서는 제약 조건 충돌을 다음과 같은 세 종류로 구분합니다.
예를 들어 대상 복제본에 이미 있는 파일과 이름 및 위치가 같은 파일을 원본 공급자가 보내는 경우처럼 대상 저장소에 있는 다른 항목과 충돌하여 항목을 저장할 수 없는 경우 중복 충돌이 발생합니다.
원본 공급자가 파일을 대상 복제본에 없는 디렉터리에 저장하도록 보내는 경우처럼 항목에 필요한 부모 항목이 없어서 계층 구조 데이터 저장소에 해당 항목을 저장할 수 없는 경우 손실된 부모 충돌이 발생합니다.
다른 제약 조건 충돌은 원본 공급자가 보내는 파일이 너무 커서 대상 복제본에 저장할 수 없는 경우 또는 변경 내용이 대상 복제본의 일부 비즈니스 논리를 위반하는 경우와 같이 저장할 항목이 대상 복제본의 제약 조건을 위반하는 경우 발생합니다.
제약 조건은 데이터베이스에서 공통적인 외래 키 제약 조건과 같이 항목 저장소의 특정 기능과 관련이 있습니다. 단순 공급자는 중복 제약 조건 충돌만 지원합니다. 표준 사용자 지정 공급자의 충돌 처리에 대한 자세한 내용은 제약 조건 충돌 검색 및 해결을 참조하십시오.
충돌 처리 이해
동시성 충돌 및 제약 조건 충돌을 처리하는 방법을 결정하려면 다음과 같은 두 가지 중요한 질문에 대답해야 합니다.
동기화 중에 충돌이 자동으로 해결되어야 합니까, 아니면 응용 프로그램이 충돌을 해결할 수 있도록 충돌이 검색될 때 응용 프로그램에 알려야 합니까?
원본 또는 대상을 우선으로 적용하도록 지정하여 모든 충돌을 해결해야 합니까, 아니면 고급 충돌 처리가 필요합니까? 예를 들어 동시성 충돌에서 원본 및 대상 데이터를 두 복제본에 모두 적용되는 단일 항목에 병합할 수 있습니다.
이러한 질문에 대답한 후에는 충돌이 발생할 때 Sync Framework에서 어떻게 동작할지 지정할 수 있습니다.
동시성 충돌 및 중복 제약 조건 충돌에 대한 해결 정책을 지정합니다. 정책을 통해 Sync Framework에서 충돌을 자동으로 해결할지 여부 또는 응용 프로그램에서 기본적으로 충돌을 처리하는 이벤트에 응답할지 여부를 결정합니다.
관리 코드: 공급자가 Configuration 속성에 의해 노출되는 KnowledgeSyncProviderConfiguration 개체의 ConflictResolutionPolicy 및 CollisionConflictResolutionPolicy 열거형에서 값을 지정합니다.
비관리 코드: 응용 프로그램에서 동기화 세션을 시작할 때 CONFLICT_RESOLUTION_POLICY가 ISyncSession::Start에 전달됩니다. 이 릴리스에서는 비관리 코드에 대해 COLLISION_CONFLICT_RESOLUTION_POLICY를 전달할 수 없습니다.
기본값 이외의 정책을 지정하면 충돌이 발생할 때 Sync Framework에서 적절한 충돌 해결 동작을 설정합니다. 예를 들어 동시성 충돌에 "원본 우선" 정책을 지정하면 동기화 세션 중에 동시성 충돌이 검색될 경우 "원본 우선" 동작이 설정됩니다. 하나 이상의 해결 정책에 대해 기본값을 그대로 사용할 경우 공급자 또는 응용 프로그램이 충돌이 검색될 때 발생하는 이벤트에 응답해야 합니다. 공급자는 다음 메서드를 구현하여 응답할 수 있습니다.
관리 코드: OnItemConflicting 및 OnItemConstraint
비관리 코드: ISimpleSyncEvents::OnConcurrencyConflict 및 ISimpleSyncEvents::OnConstraintConflict
공급자가 이러한 메서드를 구현하지 않은 경우 응용 프로그램에서 해결 동작을 설정할 수 있도록 다음과 같은 응용 프로그램 콜백이 사용됩니다. 응용 프로그램이 이러한 이벤트에 응답하지 않으면 이후 동기화 세션이 시작될 때까지 충돌 해결이 지연됩니다. 이 상황에서는 충돌되는 데이터나 응용 프로그램이 변경되기 전에는 절대 충돌이 해결되지 않습니다.
관리 코드: ItemConflicting 및 ItemConstraint
비관리 코드: ISyncCallback::OnConflict 및 ISyncConstraintCallback::OnConstraintConflict
충돌에 응답할 때 공급자 또는 응용 프로그램에서 해결 동작을 설정해야 합니다.
관리 코드: SetResolutionAction을 호출하고 ConflictResolutionAction에서 값을 전달하거나, SetResolutionAction을 호출하고 ConstraintConflictResolutionAction에서 값을 전달합니다.
비관리 코드: IChangeConflict::SetResolveActionForChange 또는 IChangeConflict::SetResolveActionForChangeUnit을 호출하고 SYNC_RESOLVE_ACTION에서 값을 전달하거나, IConstraintConflict::SetConstraintResolveActionForChange 또는 IConstraintConflict::GetConstraintResolveActionForChangeUnit을 호출하고 SYNC_CONSTRAINT_RESOLVE_ACTION에서 값을 전달합니다.
해결 동작을 설정할 수 있을 뿐만 아니라 이벤트 처리기에 사용자 지정 코드를 포함할 수도 있습니다. 예를 들어 충돌하는 항목을 처리하는 동안 사용자 인터페이스에 표시할 수 있습니다.
Sync Framework 또는 응용 프로그램에서 설정하는 일부 해결 동작의 경우 다음 인터페이스 중 하나 이상을 구현해야 합니다.
관리 코드: ISimpleSyncProviderConcurrencyConflictResolver 및 ISimpleSyncProviderConstraintConflictResolver
비관리 코드: ISimpleSyncProviderConcurrencyConflictResolver 및 ISimpleSyncProviderConstraintConflictResolver
동시성 충돌의 경우에는 이러한 인터페이스에 구현하는 해결 메서드가 업데이트-업데이트 충돌과 같은 응답하는 충돌 유형으로 구분되고, 제약 조건 충돌의 경우에는 구현하는 해결 메서드가 원본 항목 이름 바꾸기와 같은 해결 결과로 구분됩니다.
동시성 충돌의 경우 동작이 Merge(관리 코드의 경우) 또는 SRA_MERGE(비관리 코드의 경우)로 설정되어 있으면 다음과 같이 세 가지 유형의 동시성 충돌을 처리하는 메서드를 구현해야 합니다.
관리 코드: ResolveUpdateUpdateConflict, ResolveLocalDeleteRemoteUpdateConflict 및 ResolveLocalUpdateRemoteDeleteConflict
비관리 코드: ISimpleSyncProviderConcurrencyConflictResolver::ResolveUpdateUpdateConflict, ISimpleSyncProviderConcurrencyConflictResolver::ResolveLocalDeleteRemoteUpdateConflict 및 ISimpleSyncProviderConcurrencyConflictResolver::ResolveLocalUpdateRemoteDeleteConflict
충돌하는 두 항목을 나타내는 하나의 최종 항목이 있으면 구현에서 복제본과 응용 프로그램에 적합한 방식으로 충돌하는 항목을 병합해야 합니다.
중복 제약 조건 충돌의 경우 설정할 수 있는 동작을 기반으로 메서드를 구현합니다.
관리 코드(ConstraintConflictResolutionAction):
비관리 코드(SYNC_CONSTRAINT_RESOLVE_ACTION):
동작 메서드SCRA_RENAME_DESTINATIONISimpleSyncProviderConstraintConflictResolver::ModifyAndUpdateRemoteItem 및 ISimpleSyncProviderConstraintConflictResolver::ModifyAndInsertRemoteItemSCRA_RENAME_SOURCEISimpleSyncProviderConstraintConflictResolver::ModifyLocalItem
관리 코드 예제
이 샘플에서는 동시성 충돌 및 제약 조건 충돌에 대한 충돌 처리 정책이 ApplicationDefined
의 기본값으로 유지되어 있습니다. 즉, 응용 프로그램에서 ItemConflicting 및 ItemConstraint 이벤트를 등록하고 동기화를 처리하는 동안 충돌이 발생할 경우 이를 해결하는 동작을 지정합니다. 다음 코드 예제에서는 MyFullEnumerationSimpleSyncProvider
의 생성자에 지정된 이벤트 처리기를 보여 줍니다.
this.ItemConstraint += new EventHandler<SimpleSyncItemConstraintEventArgs>(OnItemConstraint);
this.ItemConflicting += new EventHandler<SimpleSyncItemConflictingEventArgs>(OnItemConflicting);
AddHandler Me.ItemConstraint, AddressOf HandleItemConstraint
다음 코드 예제에서는 충돌 해결 동작을 Merge
로 설정하는 이벤트 처리기를 보여 줍니다.
void OnItemConstraint(object sender, SimpleSyncItemConstraintEventArgs e)
{
// Set the resolution action for constraint conflicts.
// In this sample, the provider checks for duplicates in InsertItem, and this event would
// fire if a duplicate occurred.
e.SetResolutionAction(ConstraintConflictResolutionAction.Merge);
}
void OnItemConflicting(object sender, SimpleSyncItemConflictingEventArgs e)
{
// Set the resolution action for concurrency conflicts.
e.SetResolutionAction(ConflictResolutionAction.Merge);
}
Private Sub HandleItemConstraint(ByVal sender As Object, ByVal e As SimpleSyncItemConstraintEventArgs)
' Set the resolution action for constraint conflicts.
' In this sample, the provider checks for duplicates in InsertItem, and this event would
' fire if a duplicate occurred.
e.SetResolutionAction(ConstraintConflictResolutionAction.Merge)
End Sub
Private Sub HandleItemConflicting(ByVal sender As Object, ByVal e As SimpleSyncItemConflictingEventArgs)
' Set the resolution action for concurrency conflicts.
e.SetResolutionAction(ConflictResolutionAction.Merge)
End Sub
다음 코드 예제에서는 제약 조건 충돌에 대한 Merge 해결 동작에 응답하도록 구현된 MergeConstraintConflict 메서드를 보여 줍니다.
public void MergeConstraintConflict(object itemData,
ConflictVersionInformation conflictVersionInformation,
IEnumerable<SyncId> changeUnitsToMerge,
ItemFieldDictionary localConflictingItem,
ItemFieldDictionary keyAndExpectedVersion,
RecoverableErrorReportingContext recoverableErrorReportingContext,
out ItemFieldDictionary updatedKeyAndVersion)
{
ItemTransfer transfer = (ItemTransfer)itemData;
ItemData dataCopy = new ItemData(transfer.ItemData);
// Combine the conflicting data.
ItemData mergedData = (_store.Get(transfer.Id)).Merge((ItemData)dataCopy);
// We are doing a merge so we must delete the old conflicting item from our store.
ulong idConflicting = (ulong)localConflictingItem[CUSTOM_FIELD_ID].Value;
_store.DeleteItem(idConflicting);
// Now create the new merged data in the store.
if (_store.Contains(transfer.Id))
{
_store.UpdateItem(transfer.Id, dataCopy);
}
else
{
_store.CreateItem(mergedData, transfer.Id);
}
updatedKeyAndVersion = _store.CreateItemFieldDictionary(transfer.Id);
}
Public Sub MergeConstraintConflict(ByVal itemData As Object, ByVal conflictVersionInformation As ConflictVersionInformation, ByVal changeUnitsToMerge As IEnumerable(Of SyncId), ByVal localConflictingItem As ItemFieldDictionary, ByVal keyAndExpectedVersion As ItemFieldDictionary, ByVal recoverableErrorReportingContext As RecoverableErrorReportingContext, _
ByRef updatedKeyAndVersion As ItemFieldDictionary) Implements ISimpleSyncProviderConstraintConflictResolver.MergeConstraintConflict
Dim transfer As ItemTransfer = DirectCast(itemData, ItemTransfer)
Dim dataCopy As New ItemData(transfer.ItemData)
' Combine the conflicting data.
Dim mergedData As ItemData = (_store.[Get](transfer.Id)).Merge(DirectCast(dataCopy, ItemData))
' We are doing a merge so we must delete the old conflicting item from our store.
Dim idConflicting As ULong = CULng(localConflictingItem(CUSTOM_FIELD_ID).Value)
_store.DeleteItem(idConflicting)
' Now create the new merged data in the store.
If _store.Contains(transfer.Id) Then
_store.UpdateItem(transfer.Id, dataCopy)
Else
_store.CreateItem(mergedData, transfer.Id)
End If
updatedKeyAndVersion = _store.CreateItemFieldDictionary(transfer.Id)
End Sub