处理微软MSF同步框架中的数据冲突

原创
开发 项目管理
在任何程序或从多个数据源同步数据的框架中都不能避免数据冲突,微软同步框架(Microsoft Sync Framework即MSF)也不例外。但MSF有内置的特性帮助开发人员处理大部分数据冲突,我们一起来看看ADO.NET v1.0的MSF服务是如何帮助开发人员减少处理冲突的负担的

【51CTO独家特稿】如果你刚刚接触微软同步框架,你可以通过本文开始学习,在下面的示例中,我们假设你已经对MSF框架有所了解。

首先,我们需要理解什么是数据冲突,它是怎么产生的。图1显示了最常见的数据冲突,当两个源同时更新一行数据时的情况。例如,假设有两个客户端(客户端A和客户端B)更新了本地数据缓存,然后同时同步到同一个服务器,此时客户端A和B接收到的是表x的同一个拷贝,客户端A更新了表x中第17行的电话号码,然后同步回服务器,与此同时,客户端B更新了表x中第17行的email地址,当客户端B同步回服务器时,冲突就发生了,此时服务器要决定究竟那个要写入主拷贝中。象这样的例子在应用程序逻辑中也存在,MSF提供了两个不同的方法来定义这个逻辑。

图- 1 常见的同步冲突实例

冲突类型和解决办法

MSF定义了五个不同的冲突类型,它定义为ConflictType枚举量:

◆ ClientInsertServerInsert 以相同的主键创建一个新行。

◆ ClientUpdateServerUpdate 相同的行被更新,这是最常见的冲突,如图1所示。

◆ ClientUpdateServerDelete 在客户端更新的行,但在服务器上已经被删除了。

◆ ClientDeleteServerUpdate 在客户端删除的行,但在服务器上已经更新了。

◆ ErrorsOccurred 当发生错误时使用“catch all”(停止一切)预防行被插入、更新或删除。

当你看了图1中的例子后,你可能会认为只有当同步计划是双向的时候才会引发冲突,但并不仅仅是这样。设想一个只上载的情况,客户端不关心在服务器上的更新,它只是想将新的信息提交给服务器,该客户端会创建一行数据并同步到客户端。在某些情况下,有些讨厌的用户会打乱服务器判断数据行的行为,可能造成服务器认为这一行数据不再需要,因此将其删除了。在那个时候,客户端会对那一行做出修改并同步回服务器,但这也会造成冲突,因为客户端更新的行,在服务器上已经被删除了。这种情况下,只有将更新操作改为插入操作才能解决这个冲突。

除上面描述的冲突类型外,MSF还定义了三个内置的行为来解决冲突,它们定义在ApplyAction枚举量中:

◆ Continue 这是默认的行为,它允许你继续到列表中下一个冲突。

◆ RetryApplyingRow 将会重新尝试应用对行的修改,除非你使用某种方法修改了数据,否则就会失败(通常是在代码中使用自定义的冲突解决方案,匹配业务逻辑解决冲突)。

◆ RetryWithForceWrite 将会强制应用程序修改行(覆盖任何冲突的数据)。

在接下来的内容中,我们将会看到这些行为对某些冲突类型的处理结果。

使用ApplyChangeFailed解决冲突

知道冲突类型很重要,但你也需要知道是哪一行发生了冲突,MSF在DbServerSyncProvider和SqlCeClientSyncProvider上都提供了ApplyChangeFailed事件,允许你审查冲突信息,然后决定如何处理。在服务器和客户端SyncProvider上都有可能引发事件,取决于同步的阶段,ApplyChangeFailedEventArgs对象具有Action和Conflict属性,Action属性用于解决冲突,只要将其设为前一小节描述的ApplyAction类型的一个值即可;Conflict属性描述了更详细的冲突信息,如它的类型和发生冲突的行。

ApplyChangeFailedEventArgs对象还有一个Context属性,它允许你修改正在同步的数据,你可以使用它创建自己的冲突解决方案,这样你在处理复杂数据冲突时可以更加得心应手。

我们来看一些例子吧,我们创建了一个项目,显示一个跟踪顾客喜欢的数字的表,窗体的上半部分显示了服务端数据拷贝,窗体的下半部分显示了客户端缓存中的数据拷贝,我们可以修改任何一半的数据,然后保存数据到服务器和客户端,接着尝试同步数据,如果遇到数据冲突,会显示一个自定义窗体,让我们选择一个ApplyAction类型来解决冲突。

图- 2 冲突解决方案示例窗体

我们通过修改数据缓存文件(.sync)的后端代码使用partial类将ApplyChangeFailed事件联系起来,在我们的例子代码如下:

public partial class DataConflictsDataCacheServerSyncProvider

{

partial void OnInitialized()

{

this.ApplyChangeFailed += new

System.EventHandler(

DataConflictsDataCacheServerSyncProvider_ApplyChangeFailed);}

void DataConflictsDataCacheServerSyncProvider_ApplyChangeFailed(object sender,

Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs e)

{

ConflictResolverForm cr = new ConflictResolverForm();

cr.Text = "Server Data Conflict Detected";

cr.ApplyChangeEventArgs = e;

cr.ShowDialog();

}

}

public partial class DataConflictsDataCacheClientSyncProvider

{

void DataConflictsDataCacheClientSyncProvider_ApplyChangeFailed(

object sender, Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs e)

{

ConflictResolverForm cr = new ConflictResolverForm();

cr.Text = "Client Data Conflict Detected";

cr.ApplyChangeEventArgs = e;

cr.ShowDialog();

}

}

我们还必须将下面的代码添加到客户端SyncProvider的构造器中(你可以在.designer.cs代码文件中找到它):

this.ApplyChangeFailed +=new

System.EventHandler

(DataConflictsDataCacheClientSyncProvider_ApplyChangeFailed);

在ConflictResolverForm中,我们通过设置合适的ApplyAction告诉同步框架如何解决冲突,如下:

applyChangeEventArgs.Action = Microsoft.Synchronization.Data.ApplyAction.Continue;

applyChangeEventArgs.Action = Microsoft.Synchronization.Data.ApplyAction.RetryApplyingRow;

applyChangeEventArgs.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite;

这些行为将会一一为你展示。

#p#

例1. ClientUpdateServerUpdate

在这个例子中,我们同时修改了服务端和客户端CustomerId等于2的行,然后尝试重新同步,在服务器端,我们修改了FirstName字段的值为Chad,在客户端,我们修改FavoriteNumber字段的值为5。在服务器端SyncProvider上我们遇到了ClientUpdateServerUpdate冲突:

图- 3 在服务器上遇到了ClientUpdateServerUpdate冲突

如果我们选择继续,服务器端的修改就会胜出,客户端的修改将会丢失:

图- 4 在服务器上遇到ClientUpdateServerUpdate冲突选择了ApplyAction.Continue行为后的结果

如果我们选择了RetryApplyingRow,会重新陷入错误,因为我们还没有修改数据,因此我们仅仅需要再次显示我们的冲突解决窗体。

如果我们选择RetryWithForceWrite,客户端的修改会胜出,而服务器端的修改就会丢失:

图- 5 在服务器上遇到ClientUpdateServerUpdate冲突选择了ApplyAction.RetryWithForceWrite行为后的结果

例2. ClientInsertServerInsert

在这个例子中,我们在服务器上插入了一行数据,CustomerId(主键)等于3,我们也在客户端插入了一行数据,CustomerId(主键)也等于3。

图- 6 在服务器和客户端都插入一行数据

当我们尝试同步时,在服务器SyncProvider上我们遇到了ClientInsertServerInsert冲突:

图- 7 在服务器上遇到的ClientInsertServerInsert冲突

如果我们选择继续,我们会遇到另一个冲突ClientInsertServerInsert,不过这次冲突是在客户端SyncProvider上:

图- 8 在客户端上的ClientInsertServerInsert冲突

如果我们再次选择继续,你会看到两边的数据都没有改变,每个数据库都保持了它们自己的修改,实际上就是忽略了冲突。

图- 9 在服务器上遇到ClientInsertServerInsert冲突,在客户端上选择ApplyAction.Continue行为后的结果

和前面的例子一样,如果我们选择RetryApplyingRow,我们将会继续得到一个冲突对话框。

如果我们选择RetryWithForceWrite,在客户端上不会再出现冲突,客户端的修改将会上载,覆盖服务器上的修改:

图- 10 在服务器上遇到ClientInsertServerInsert冲突,选择ApplyAction.RetryWithForceWrite行为后的结果

使用ConflictResolver解决客户端冲突

如果指定一种解决方案不能满足你的需要,并且你想精简你的代码,MSF在SqlCeClientSyncProvider上提供了一个附加属性ConflictResolver,你可以单独设置它的属性为下面三个值的一个来解决所有五种冲突:

◆ ClientWins

◆ ServerWins

◆ FireEvent

默认情况下,最后一个选项FireEvent是默认值。

设置ConflictResolver的代码可以和ApplyChangeFailed处理程序一起添加到客户端SyncProvider的构造器中:

this.ConflictResolver.ClientDeleteServerUpdateAction = 

Microsoft.Synchronization.Data.ResolveAction.ServerWins;

this.ConflictResolver.ClientUpdateServerDeleteAction =

Microsoft.Synchronization.Data.ResolveAction.ClientWins;

this.ConflictResolver.ClientInsertServerInsertAction =

Microsoft.Synchronization.Data.ResolveAction.FireEvent;

this.ConflictResolver.ClientUpdateServerUpdateAction =

Microsoft.Synchronization.Data.ResolveAction.FireEvent;

this.ApplyChangeFailed +=new 

System.EventHandler

(DataConflictsDataCacheClientSyncProvider_ApplyChangeFailed);

在上面的例子中,我们总是允许更新胜过删除,我们通过在为ApplyChangeFailed事件定义的处理程序中自定义业务逻辑让更新冲突得到解决。

小结

所有数据同步解决方案都需要数据冲突解决方案,使用微软的同步框架(MSF),它有一套内置的冲突解决机制,让你可以定义简单的冲突解决方案(ConflictResolver),也可以定义复杂的冲突的解决方案(通过ApplyChangeFailed事件自定义业务逻辑解决方案)。

【编辑推荐】

  1. 项目管理利刃之MSF
  2. 解读MSF团队管理的秘密
  3. 软件项目管理总体流程设计
责任编辑:彭凡 来源: 51CTO.com
相关推荐

2010-03-21 19:05:19

微软MSF

2022-05-31 09:52:04

Edge浏览器微软

2013-08-14 09:48:02

微软REEF

2017-09-09 16:22:51

PHP-MSF服务器服务框架

2010-09-16 09:44:56

2009-05-26 10:21:07

2023-11-06 08:01:09

Go同步异步

2012-05-17 09:28:06

代码审查Java代码

2010-03-30 17:27:47

Visual Stud

2017-09-20 07:37:13

Swoole企业微服务框架

2009-03-24 08:56:23

数据同步多线程Java

2017-09-06 17:05:54

大数据处理流程处理框架

2018-04-03 10:33:15

大数据

2010-09-26 13:30:08

DHCP协议故障处理

2013-12-16 17:17:01

OpenMp数据处理

2013-03-14 09:54:54

jQueryJS

2021-08-08 08:04:38

微软macOS OneDrive

2010-04-20 14:18:23

2023-11-23 12:12:00

2021-04-02 12:55:14

数据处理Apache Falc开发
点赞
收藏

51CTO技术栈公众号