我正在使用在集线器中配置的Sync Framework v2.1< - >说话时尚。 Hub:使用SqlSyncProvider的SQL Server 2012。 Spokes:使用SqlSyncProvider的LocalDb 2012。每个辐条'数据库从服务器开始作为已还原的备份,然后对其执行PostRestoreFixup。在调查此问题时,我还尝试从一个空的辐条数据库开始,该数据库的模式和数据是通过配置和初始的仅下载同步创建的。
假设两个辐条(A& B)和一个中央集线器(让我们称之为H)。它们每个都有一个包含一条记录的表,它们都是同步的。
Spoke B更改相同的记录并进行同步,从而导致与步骤1中所做的更改发生冲突。 B的记录被H覆盖,H的记录保持原样。这是预期/期望的结果。但是,协调器返回的SyncOperationStatistics建议在H处进行更改。我已经尝试了两个SyncDirectionOrder方向,这些结果如下:
- DownloadAndUpload (H's local_update_peer_timestamp and last_change_datetime are updated) --> * Download changes total: 1 * Download changes applied: 1 * Download changed failed: 0 * Upload changes total: 1 * Upload changes applied: 1 * Upload changed failed: 0 - UploadAndDownload (H's local_update_peer_timestamp is updated)--> * Upload changes total: 1 * Upload changes applied: 1 * Upload changed failed: 0 * Download changes total: 1 * Download changes applied: 1 * Download changed failed: 0
事实上,当Spoke A再次同步时,记录会从H下载,即使H的记录没有改变。为什么呢?
由此产生的问题是,例如,如果Spoke A对步骤#2和3之间的记录进行了另一次更改,则该更改将(错误地)标记为冲突,并将在步骤#3中被覆盖。 / p>
这里有一些简化的代码来证明这个问题,或者说是我的问题。请注意,我已经实现了提供程序的ApplyChangeFailed处理程序,以便服务器获胜,无论SyncDirectionOrder如何:
private const string ScopeName = "TestScope";
private const string TestTable = "TestTable";
public static SyncOperationStatistics Synchronize(SyncEndpoint local,SyncEndpoint remote, EventHandler<DbSyncProgressEventArgs> eventHandler)
{
using (var localConn = new SqlConnection(local.ConnectionString))
using (var remoteConn = new SqlConnection(remote.ConnectionString))
{
// provision the remote server if necessary
//
var serverProvision = new SqlSyncScopeProvisioning(remoteConn);
if (!serverProvision.ScopeExists(ScopeName))
{
var serverScopeDesc = new DbSyncScopeDescription(ScopeName);
var serverTableDesc = SqlSyncDescriptionBuilder.GetDescriptionForTable(TestTable, remoteConn);
serverScopeDesc.Tables.Add(serverTableDesc);
serverProvision.PopulateFromScopeDescription(serverScopeDesc);
serverProvision.Apply();
}
// provision locally (localDb), if necessary, bringing down the server's scope
//
var clientProvision = new SqlSyncScopeProvisioning(localConn);
if (!clientProvision.ScopeExists(ScopeName))
{
var scopeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope(ScopeName, remoteConn);
clientProvision.PopulateFromScopeDescription(scopeDesc);
clientProvision.Apply();
}
// create\initialize the sync providers and go for it...
//
using (var localProvider = new SqlSyncProvider(ScopeName, localConn))
using (var remoteProvider = new SqlSyncProvider(ScopeName, remoteConn))
{
localProvider.SyncProviderPosition = SyncProviderPosition.Local;
localProvider.SyncProgress += eventHandler;
localProvider.ApplyChangeFailed += LocalProviderOnApplyChangeFailed;
remoteProvider.SyncProviderPosition = SyncProviderPosition.Remote;
remoteProvider.SyncProgress += eventHandler;
remoteProvider.ApplyChangeFailed += RemoteProviderOnApplyChangeFailed;
var syncOrchestrator = new SyncOrchestrator
{
LocalProvider = localProvider,
RemoteProvider = remoteProvider,
Direction = SyncDirectionOrder.UploadAndDownload // also issue with DownloadAndUpload
};
return syncOrchestrator.Synchronize();
}
}
}
private static void RemoteProviderOnApplyChangeFailed(object sender, DbApplyChangeFailedEventArgs e)
{
// ignore conflicts at the server
//
e.Action = ApplyAction.Continue;
}
private static void LocalProviderOnApplyChangeFailed(object sender, DbApplyChangeFailedEventArgs e)
{
// server wins, force write at each client
//
e.Action = ApplyAction.RetryWithForceWrite;
}
重申一下,沿着开头描述的配置使用此代码,正如预期的那样,在包含冲突的辐条上覆盖冲突的行,并且该行的服务器版本保持原样(未更改) )。但是,我发现每次冲突都会导致服务器的xxx_tracking表更新,特别是local_update_peer_timestamp和last_change_datetime字段。我猜测,即使服务器的数据没有真正改变,也会导致下载到其他所有语音。这似乎是不必要的,对我来说,这是违反直觉的。