Aplicando alterações
Depois que o provedor de destino obtiver um lote de alterações e tratar os conflitos, as alterações devem ser aplicadas à réplica de destino. Normalmente, isto é feito no ProcessChangeBatch do provedor de destino (para código gerenciado) ou no método ProcessChangeBatch (para código não gerenciado), podendo ser obtido facilmente usando um objeto aplicador de alterações fornecido pelo Sync Framework.
Como alterações são aplicadas
Depois que o provedor de destino tiver o lote de alterações do provedor de origem, o provedor de destino aplica as alterações à réplica de destino. Um objeto aplicador de alterações fornecido pelo Sync Framework pode ser obtido criando um objeto NotifyingChangeApplier (para código gerenciado) ou chamando IProviderSyncServices::CreateChangeApplier (para código não aplicado). O ApplyChanges (para código gerenciado) ou o método ApplyChanges (para código não gerenciado) detecta conflitos e chama métodos no provedor de destino se aplicar alterações à réplica de destino.
Processando um item de alteração
Para processar um item de alteração típico, o aplicador de alterações chama primeiramente o LoadChangeData (para código gerenciado) ou o método ISynchronousDataRetriever::LoadChangeData (código não gerenciado) no provedor de origem para iniciar a transferência de dados. Este método retorna um object (para código gerenciado) ou uma interface IUnknown (para código não gerenciado) que representa o mecanismo de transferência de dados. O aplicador de alterações chama o SaveItemChange (para código gerenciado) ou o método ISynchronousNotifyingChangeApplierTarget::SaveChange (para código não gerenciado) no provedor de destino, passando o objeto de transferência de dados como parte do contexto de salvamento de alteração. O provedor de destino então pode transferir os dados para a réplica de destino. Quaisquer falhas na obtenção de dados ou no processamento de alterações são indicada usando o RecordRecoverableErrorForItem (para código gerenciado) ou o método ISaveChangeContext::SetRecoverableErrorOnChange (para código não gerenciado). Este método registra um erro recuperável para o item no objeto de conhecimento adquirido que está contido no lote de alterações. Como alternativa, quando conflitos de restrição forem usados, chame RecordConstraintConflictForItem (para código gerenciado) ou ISaveChangeContext2::SetConstraintConflictOnChange (para código não gerenciado) para relatar um conflito de restrição. O conflito de restrição poderá então ser resolvido conforme especificado pelo aplicativo ou pelo provedor.
Atualizando o conhecimento adquirido
Enquanto as alterações estão sendo aplicadas, o aplicador de alterações atualiza o conhecimento adquirido contido no lote de alterações. O conhecimento adquirido é o conhecimento da réplica de origem projetado nas alterações no lote de alterações e representa o que a réplica de destino aprenderá quando aplicar todas as alterações no lote de alterações. O conhecimento adquirido é atualizado das seguintes formas:
Se somente um subconjunto de alterações for aplicado devido a interrupções ou cancelamentos, o aplicador de alterações usa o operador de projeção para restringir o conhecimento somente para o conjunto de alterações que foi aplicado.
Se a aplicação de algumas alterações falhou, o aplicador de alterações também as exclui do conhecimento.
Lembre-se que os implementadores de provedor não têm de executar esse projeto, essa união e excluir operações manualmente. Isso ocorre porque o aplicador de alterações as executa em nome do provedor.
Salvando o conhecimento de destino atualizado
Depois que o conhecimento adquirido for atualizado, este é combinado com o conhecimento da réplica de destino. O provedor de destino deve substituir o conhecimento da réplica de destino por este conhecimento atomicamente. Esta atomicidade pode ser alcançada ao salvar conhecimento atualizado só uma vez por lote se todas as alterações em um lote forem aplicadas em uma única transação. O aplicador de alterações ajuda nesta tarefa chamando o StoreKnowledgeForScope (para código gerenciado) ou o método ISynchronousNotifyingChangeApplierTarget::SaveKnowledge (para código não gerenciado) no provedor de destino no fim de cada lote. O conhecimento passado para este método é o conhecimento atualizado que é aplicado à réplica de destino. Como alternativa, o provedor de destino pode chamar o GetUpdatedDestinationKnowledge (para código gerenciado) ou o método ISaveChangeContext::GetKnowledgeForScope (para código não gerenciado) para obter o conhecimento atualizado.
Quando os provedores usam unidades de alteração para representar subitens, há algumas diferenças na forma como as alterações são aplicadas. Para obter mais informações, consulte Sincronizando unidades de alteração.
Considerações especiais para réplicas hierárquicas
A sincronização de réplicas hierárquicas pode encontrar certas complicações causadas por conjuntos de alterações em lote da origem para o destino. O Sync Framework não oferece suporte para o conceito de hierarquia de dados. Portanto, é função dos provedores tratar estas situações corretamente.
A complicação mais comum é a ordem das relações pai e filho nas operações de atualização. Por exemplo, considere o seguinte cenário:
A réplica de origem criou uma pasta nova e um conjunto de itens novos dentro desta.
O provedor de destino solicita alterações do provedor de origem. O provedor de origem envia uma lista de alterações em dois lotes. No entanto, o lote de alterações que contém a criação da pasta pai chega depois do lote de alterações que contém os itens filho.
O provedor de destino deve decidir onde armazenar o conjunto de itens que chegaram no primeiro lote, pois as informações sobre onde armazená-los não chegarão até o segundo lote.
Reduzindo atualizações hierárquicas
Se houver atualizações, o modo mais simples de reduzir complexidades de relação pai/filho é tornar o provedor de origem responsável por ordenar as IDs globais. Dessa forma os itens pai sempre chegam antes dos itens filho.
Quando os provedores de destino lidarem com a transmissão de atualizações feitas em um repositório hierárquico, estes podem receber relações pai/filho fora de ordem. Os provedores de destino devem poder se recuperar desta situação descartando a alteração fora de ordem e observando uma exceção no conhecimento destes ou enfileirando a alteração a ser aplicada depois. Como o tamanho dos itens pode ser grande, apenas descartar a alteração e observar exceções de conhecimento é provavelmente a abordagem mais efetiva.
Reduzindo exclusões hierárquicas
Os provedores de destino determinam se um item é um item de contêiner. Para contêineres vazios, as exclusões podem ocorrer imediatamente. No entanto, se o contêiner tiver itens que não foram marcados para exclusão, o provedor terá as seguintes opções:
Enfileire as exclusões para processamento posterior. Depois que todos os filhos do contêiner forem marcados para exclusão, as exclusões reais podem ser ativadas.
Descarte esta solicitação e defina uma exceção no conhecimento para indicar o recebimento fora de ordem de um item.
Para lidar com cenários nos quais um pai é excluído na hierarquia e então um filho é adicionado, a seguinte regra é observada: exclusões enfileiradas são válidas somente até o fim de uma sessão por pares e não são persistidos entre os participantes.
Consulte também
Referência
Interface ISynchronousNotifyingChangeApplier
ISynchronousNotifyingChangeApplierTarget::SaveKnowledge
Interface ISynchronousDataRetriever
ISaveChangeContext Interface
NotifyingChangeApplier
StoreKnowledgeForScope
IChangeDataRetriever
SaveChangeContext