应用变更
在目标提供程序获得变更批并处理冲突之后,必须将变更应用于目标副本。这通常可以在目标提供程序的 ProcessChangeBatch(对于托管代码)或 ProcessChangeBatch(对于非托管代码)方法中完成,并且,通过使用由 Sync Framework 提供的变更应用方对象,能够以最简单的方式实现此目标。
如何应用变更
在目标提供程序从源提供程序获得变更批之后,目标提供程序将变更应用于目标副本。可以通过创建 NotifyingChangeApplier 对象(对于托管代码)或调用 IProviderSyncServices::CreateChangeApplier(对于非托管代码)获得由 Sync Framework 提供的变更应用方对象。ApplyChanges(对于托管代码)或 ApplyChanges(对于非托管代码)方法检测冲突并对于目标提供程序调用方法,以便将变更应用于目标副本。
处理变更项
为了处理典型的变更项,变更应用方首先对于源提供程序调用 LoadChangeData(对于托管代码)或 ISynchronousDataRetriever::LoadChangeData(非托管代码)方法以开始数据传输。此方法将返回表示数据传输机制的 object(对于托管代码)或 IUnknown 接口(对于非托管代码)。然后,变更应用方对于目标提供程序调用 SaveItemChange(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveChange(对于非托管代码)方法,并将数据传输对象作为保存变更上下文的一部分传递。然后,目标提供程序将数据传输到目标副本。将通过使用 RecordRecoverableErrorForItem(对于托管代码)或 ISaveChangeContext::SetRecoverableErrorOnChange(对于非托管代码)方法指示任何未能获得数据或处理变更失败的情况。此方法在变更批包含的已知知识对象中对于此项记录一个可恢复错误。此外,当使用约束冲突时,调用 RecordConstraintConflictForItem(对于托管代码)或 ISaveChangeContext2::SetConstraintConflictOnChange(对于非托管代码)以报告约束冲突。然后,可以按照应用程序或提供程序指定的方式解决约束冲突。
更新已知知识
当正在应用变更时,变更应用方将更新变更批中包含的已知知识。已知知识指投影到变更批中的变更的源副本知识,它表示当目标副本应用变更批中的所有变更时,目标副本将了解到的知识。可以通过以下方式更新已知知识:
如果由于中断或取消而只应用了变更的子集,则变更应用方将使用 project 运算符将知识仅限制为已应用的这组变更。
如果应用某些变更时失败,变更应用方也会从知识中排除这些变更。
请注意,提供程序实现方不必手动执行这些投影、联合和排除操作。这是因为变更应用方将代表提供程序执行这些操作。
保存更新的目标知识
更新已知知识后,更新后的已知知识将与目标副本的知识合并。目标提供程序必须以原子方式使用此知识替换目标副本的知识。如果在一个事务中应用批中的所有变更,可以通过每批仅保存一次更新的知识来实现这种原子性。变更应用方可以通过在每批结束时对目标提供程序调用 StoreKnowledgeForScope(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveKnowledge(对于非托管代码)方法来帮助实现此目标。传递到此方法的知识是要应用到目标副本的已更新知识。此外,目标提供程序也可以调用 GetUpdatedDestinationKnowledge(对于托管代码)或 ISaveChangeContext::GetKnowledgeForScope(非托管代码)方法以获得更新的知识。
当提供程序使用变更单位表示子项时,在应用变更的方法上将存在一些差别。有关更多信息,请参见同步变更单位。
分层副本的特殊注意事项
同步分层副本时可能会遇到某些难题,这些难题是在从源到目标对变更集进行批处理时产生的。Sync Framework 不支持数据层次结构的概念。因此,正确地处理这些情况将完全取决于提供程序。
最常见的难题是更新操作中父子关系的顺序。例如,请考虑以下方案:
源副本已创建了一个新文件夹以及此文件夹中的一组新项。
目标提供程序从源提供程序请求变更。源提供程序分两批发送其变更列表。然而,包含父文件夹的创建的变更批将在包含子项的变更批之后到达。
目标提供程序必须确定在何处存储在第一批中已到达的这组项,因为有关存储这些项的位置的信息将不会在第二批之前到达。
减少分层更新
如果具有更新,则减少父/子关系复杂性的最简单方法是让源提供程序负责对全局 ID 进行排序。这样,父项将始终在其子项之前到达。
当目标提供程序处理在分层存储区中所做更新的传输时,它们可能收到无序的父/子关系。目标提供程序必须能够通过删除无序变更并在其知识中记录一个异常,或通过对稍后要应用的变更进行排队,以便从这种情形中恢复。因为项的大小可能很大,所以,只删除变更并记录知识异常可能是最有效的方法。
减少分层删除
目标提供程序确定某个项是否为容器项。对于空容器,将立即执行删除。然而,如果容器包含尚未标记为予以删除的项,则提供程序具有以下选项:
对删除进行排队以稍后进行处理。在容器的所有子项被标记为予以删除后,可以触发实际删除。
删除此请求并在知识中设置一个异常,以指示所收到的项的次序不正确。
若要应对在层次结构中删除父项后添加子项的方案,应遵循以下规则:已排队的删除仅在成对会话结束时才处于有效状态,并且在参与者间不持久保留已排队的删除。
请参阅
参考
ISynchronousNotifyingChangeApplier 接口
ISynchronousNotifyingChangeApplierTarget::SaveKnowledge
ISynchronousDataRetriever 接口
ISaveChangeContext 接口
NotifyingChangeApplier
StoreKnowledgeForScope
IChangeDataRetriever
SaveChangeContext