Поделиться через


Обработка конфликтов для простых поставщиков

По возможности проектируйте приложения так, чтобы избегать конфликтов. Реализация обнаружения и разрешения конфликтов приводит к повышению сложности, дополнительным затратам на обработку и увеличению сетевого трафика. В некоторых приложениях конфликты неизбежны. Например, в приложении для обработки продаж два продавца могут обслуживать одну территорию. Оба продавца могут обновлять данные для одного заказчика и заказов. Чтобы обеспечить правильное распространение изменений, вносимых в элементы сообщества синхронизации, поставщик назначения должен выполнять обнаружение и обработку конфликтов, возникающих между элементами, отправленными с поставщика источника, и элементами в реплике назначения. Sync Framework предоставляет объекты, выполняющие основной объем работы, необходимой для обнаружения и обработки конфликтов.

Sync Framework обнаруживает конфликты на уровне элемента или базовой единицы, и Sync Framework определяет две категории конфликтов, возникающих в ходе синхронизации: конфликты параллелизма и конфликты ограничений. Конфликты параллелизма возникают, если один и тот же элемент или базовая единица изменяются в двух различных репликах, которые синхронизируются позже. Конфликты ограничений представляют собой конфликты, которые нарушают ограничения, наложенные на элементы или базовые единицы, такие как связь папок или расположение данных с идентичными именами в пределах файловой системы. Sync Framework разделяет конфликты ограничений на следующие три типа.

  • Конфликт совпадения возникает, когда не удается сохранить элемент, поскольку он конфликтует с другим элементом в целевом хранилище. Например, поставщик источника отправляет файл, имя и путь которого совпадают с именем и путем файла, уже имеющегося в реплике назначения.

  • Конфликт отсутствия родителя возникает, когда элемент не удается сохранить в иерархическом хранилище данных, поскольку для этого необходим отсутствующий родительский элемент. Например, поставщик источника отправляет файл для сохранения в каталоге, который отсутствует в реплике назначения.

  • Другие конфликты ограничений возникают, когда сохраняемый элемент нарушает какое-либо ограничение реплики назначения. Например, исходный поставщик отправляет файл, слишком большой для размещения на реплике назначения, либо изменение нарушает какое-либо из правил бизнес-логики на реплике назначения.

Ограничения связаны с определенными возможностями хранилища элементов. Например, в базах данных широко применяются ограничения внешнего ключа. Простые поставщики поддерживают только обработку конфликтов совпадения. Дополнительные сведения об обработке конфликтов для стандартных пользовательских поставщиков см. в разделе Обнаружение и разрешение конфликтов ограничений.

Основные сведения о обработке конфликтов

Чтобы выбрать способ обработки конфликтов параллелизма и конфликтов ограничений, необходимо ответить на два главных вопроса.

  • Должны ли конфликты разрешаться автоматически в ходе синхронизации, или приложение должно получать уведомление об обнаруженных конфликтах, а затем управлять устранением конфликтов?

  • Должно ли для всех конфликтов применяться простое разрешение, когда побеждает источник или назначение, либо требуется более сложная обработка конфликтов? Например, в конфликте параллелизма может потребоваться выполнять слияние данных источника и назначения в общий элемент, который применяется в обеих репликах.

После ответа на эти вопросы можно указать действия, выполняемые Sync Framework в случае обнаружения конфликта.

  1. Укажите политику разрешения для конфликтов ограничений и конфликтов совпадения. Эта политика определяет, будет ли Sync Framework выполнять автоматическое разрешение конфликта, или приложение будет отвечать на событие для обработки конфликта.

    Если указать политику, отличную от политики по умолчанию, Sync Framework устанавливает соответствующее действие по устранению конфликтов, когда происходит конфликт. Например, если указать для конфликтов параллелизма политику «выигрывает источник», то, когда в ходе сеанса синхронизации обнаруживается конфликт такого типа, задается действие «выигрывает источник». Если принять для одной или обеих политик значение по умолчанию, то поставщик или приложение должны отвечать на события, отправляемые в момент обнаружения конфликта. Для ответа поставщика можно реализовать следующие методы.

    Если в поставщике не реализованы эти методы, то применяются следующие ответные вызовы приложения, чтобы приложение могло задавать действие по разрешению. Если приложение не отвечает на эти события, то разрешение конфликта откладывается до следующего сеанса синхронизации. В данном случае конфликт никогда не будет разрешен, если не изменится ни приложение, ни сами конфликтующие данные.

    В ответ на конфликт поставщики или приложение должны задать действие по разрешению.

    Помимо задания действия по разрешению, можно включить в обработчик события пользовательский код. Например, можно выводить в пользовательском интерфейсе конфликтующие элементы по мере их обработки.

  2. Для некоторых действий по разрешению, задаваемых Sync Framework или приложением, необходимо реализовать один или оба следующих интерфейса.

    Для конфликтов параллелизма методы разрешения, реализуемые для этих интерфейсов, отличаются в зависимости от типа конфликтов, например конфликт двух операций обновления. Методы разрешения, реализуемые для конфликтов ограничений, различаются в зависимости от результата разрешения, например переименование исходного элемента.

    Если для конфликтов параллелизма установлено действие Merge (в управляемом коде) или SRA_MERGE (в неуправляемом коде), необходимо реализовать следующие методы, обрабатывающие три типа конфликтов параллелизма.

    Реализация должна выполнять слияние конфликтующих элементов наиболее подходящим для реплики и приложения способом при условии, что один конечный элемент представляет два конфликтующих элемента.

    Для конфликтов совпадения реализуйте методы, основанные на задаваемых действиях.

Пример управляемого кода

В этом образце для обработки конфликтов параллелизма и конфликтов ограничений используются политики по умолчанию, определенные объектом 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

В следующем примере кода показан метод 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

См. также

Основные положения

Реализация простого пользовательского поставщика
Как создать управляемый простой поставщик