Answered by:
Multiple scope problem - SQLExpress2008 - SQLCe

Question
-
Hello,
I am trying to sync a SQLExpress 2008 and a SQLCE db with 2 scopes. One scope sends the changes from 5 tables to the CE db amd the other scope sends changes from a sixth table both ways. Here is how I am provision the DB's (I started with the code in the MSDN example http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=sync&ReleaseId=3423 :public SqlSyncProvider ConfigureSqlSyncProvider(string hostName) { SyncServerSQL svrConnString = new SyncServerSQL(); SqlSyncProvider provider = new SqlSyncProvider(); provider.ScopeName = SyncUtils.ScopeNameToClient; provider.Connection = new SqlConnection(svrConnString.SqlConnString); DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription("TestToClient"); SqlSyncScopeProvisioning serverConfig = new SqlSyncScopeProvisioning((System.Data.SqlClient.SqlConnection)provider.Connection); if (!serverConfig.ScopeExists("TestToClient")) { scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Table_001", (System.Data.SqlClient.SqlConnection)provider.Connection)); scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Table_002", (System.Data.SqlClient.SqlConnection)provider.Connection)); scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Table_003", (System.Data.SqlClient.SqlConnection)provider.Connection)); scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Table_004", (System.Data.SqlClient.SqlConnection)provider.Connection)); scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Table_005", (System.Data.SqlClient.SqlConnection)provider.Connection)); serverConfig.PopulateFromScopeDescription(scopeDesc); serverConfig.SetCreateTableDefault(DbSyncCreationOption.Skip); serverConfig.Apply(); } DbSyncScopeDescription scopeDescBothWays = new DbSyncScopeDescription("TestBothWays"); SqlSyncScopeProvisioning serverConfigBothWays = new SqlSyncScopeProvisioning((System.Data.SqlClient.SqlConnection)provider.Connection); if (!serverConfigBothWays.ScopeExists("TestBothWays")) { scopeDescBothWays.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Table_006", (System.Data.SqlClient.SqlConnection)provider.Connection)); serverConfigBothWays.PopulateFromScopeDescription(scopeDescBothWays); serverConfigBothWays.SetCreateTableDefault(DbSyncCreationOption.Skip); serverConfigBothWays.Apply(); } provider.BatchApplied += new EventHandler<DbBatchAppliedEventArgs>(provider_BatchApplied); provider.BatchSpooled += new EventHandler<DbBatchSpooledEventArgs>(provider_BatchSpooled); return provider; } public SqlCeSyncProvider ConfigureCESyncProvider(SqlCeConnection sqlCeConnection) { SqlCeSyncProvider provider = new SqlCeSyncProvider(); provider.ScopeName = SyncUtils.ScopeNameToClient; provider.Connection = sqlCeConnection; SyncServerSQL svrConnString = new SyncServerSQL(); SqlConnection serverConn = new SqlConnection(svrConnString.SqlConnString); DbSyncScopeDescription scopeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope(SyncUtils.ScopeNameToClient, serverConn); SqlCeSyncScopeProvisioning serverConfig = new SqlCeSyncScopeProvisioning(sqlCeConnection,scopeDesc); DbSyncScopeDescription scopeDescBothWays = SqlSyncDescriptionBuilder.GetDescriptionForScope(SyncUtils.ScopeNameBothWays, serverConn); SqlCeSyncScopeProvisioning serverConfigBothWays = new SqlCeSyncScopeProvisioning(sqlCeConnection, scopeDescBothWays); if (!serverConfig.ScopeExists(SyncUtils.ScopeNameToClient) || !serverConfigBothWays.ScopeExists(SyncUtils.ScopeNameBothWays) || SyncUtils.ScopeRebuild) { SqlCeSyncScopeDeprovisioning clientSqlCeDepro = new SqlCeSyncScopeDeprovisioning(sqlCeConnection); try { clientSqlCeDepro.DeprovisionStore(); } catch { } serverConfig.Apply(); serverConfigBothWays.Apply(); } provider.BeginSnapshotInitialization += new EventHandler<DbBeginSnapshotInitializationEventArgs>(provider_BeginSnapshotInitialization); provider.EndSnapshotInitialization += new EventHandler<DbEndSnapshotInitializationEventArgs>(provider_EndSnapshotInitialization); provider.BatchApplied += new EventHandler<DbBatchAppliedEventArgs>(provider_BatchApplied); provider.BatchSpooled += new EventHandler<DbBatchSpooledEventArgs>(provider_BatchSpooled); return provider; }
The syncronzation to the client works, but when I try to to the 2-way syncronization I get the following error:
Cannot apply changes because the local provider does not have adapters configured for the following tables that were received from the remote provider: Table_001, Table_002, Table_003, Table_004, Table_005. Ensure that the correct adapters have been added to both providers for Scope 'Test_BothWays', and that any table mapping has been correctly configured.
If I add Tables 001...005 to the 2-way scope, I get the same error but only for Table_006
If I then add Table_006 to the client only scope, both synconizations run without error.Can anyone point out if I am missing something obvious in trying to make the 2 scopes work?
Thanks in advance.
HankMonday, March 21, 2011 2:34 PM
Answers
-
your ConfigureSqlSyncProvider and ConfigureCESyncProvider are provisioning two scopes, however, you are setting the provider.ScopeName to ScopeNameToClient. So when they get added to the collection, their scopenames are both ScopeNameToClient.
- Marked as answer by HankAnzis Monday, March 21, 2011 4:56 PM
Monday, March 21, 2011 4:16 PM
All replies
-
can you post the code snippet for the part you're synchronizing?Monday, March 21, 2011 3:04 PM
-
Sure,
Here is the code to do the synchronization in both directions
private void doSynchronizeBothWays() { RelationalSyncProvider srcProvider = providersCollection["Server"]; RelationalSyncProvider destinationProvider = providersCollection["Client 1"]; SyncDirectionOrder determinedSyncDirection = SyncDirectionOrder.UploadAndDownload; //(destinationProvider is SqlSyncProvider) ? SyncDirectionOrder.UploadAndDownload : SyncDirectionOrder.DownloadAndUpload; RelationalProviderProxy destinationProxy = null; string hostName = (destinationProvider is SqlSyncProvider) ? ((SqlConnection)destinationProvider.Connection).DataSource : destinationProvider.Connection.Database; if (destinationProvider is SqlSyncProvider) { destinationProxy = new SqlSyncProviderProxy(SyncUtils.ScopeNameBothWays, ((SqlConnection)destinationProvider.Connection).DataSource); } else { //create a reference to the server proxy SqlSyncProviderProxy serverProxy = new SqlSyncProviderProxy(SyncUtils.ScopeNameBothWays, SyncUtils.ScopeMachine); //retrieve the scope description from the server DbSyncScopeDescription scopeDesc = serverProxy.GetScopeDescriptionBothWays(); serverProxy.Dispose(); //generate a new proxy for the client destinationProxy = new CeSyncProviderProxy(SyncUtils.ScopeNameBothWays, destinationProvider.Connection.Database, scopeDesc); } //Set memory data cache size property. 0 represents non batched mode srcProvider.MemoryDataCacheSize = this._batchSize; //No need to set memory cache size for Proxy as since the source is enabled for batching, both upload and download will //be batched. //Set batch spool location. Default value if not set is %Temp% directory. if (!string.IsNullOrEmpty(batchSpoolLocation)) { srcProvider.BatchingDirectory = batchSpoolLocation; destinationProxy.BatchingDirectory = batchSpoolLocation; } SyncOperationStatistics stats = synchronizationHelper.SynchronizeProviders(srcProvider, destinationProxy, determinedSyncDirection); TimeSpan diff = stats.SyncEndTime.Subtract(stats.SyncStartTime); destinationProxy.Dispose(); //Print Sync stats object Console.WriteLine(string.Format("Batching: {4} - Total Time To Synchronize = {0}:{1}:{2}:{3}", diff.Hours, diff.Minutes, diff.Seconds, diff.Milliseconds, (this._batchSize > 0) ? "Enabled" : "Disabled")); } }
and here is the code block that is giving the error
public SyncSessionStatistics ApplyChanges(ConflictResolutionPolicy resolutionPolicy, ChangeBatch sourceChanges, object changeData) { Log("ProcessChangeBatch: {0}", this.peerProvider.Connection.ConnectionString); DbSyncContext dataRetriever = changeData as DbSyncContext; if (dataRetriever != null && dataRetriever.IsDataBatched) { string remotePeerId = dataRetriever.MadeWithKnowledge.ReplicaId.ToString(); //Data is batched. The client should have uploaded this file to us prior to calling ApplyChanges. //So look for it. //The Id would be the DbSyncContext.BatchFileName which is just the batch file name without the complete path string localBatchFileName = null; if (!this.batchIdToFileMapper.TryGetValue(dataRetriever.BatchFileName, out localBatchFileName)) { //Service has not received this file. Throw exception throw new FaultException<WebSyncFaultException>(new WebSyncFaultException("No batch file uploaded for id " + dataRetriever.BatchFileName, null)); } dataRetriever.BatchFileName = localBatchFileName; } SyncSessionStatistics sessionStatistics = new SyncSessionStatistics(); <strong> this.peerProvider.ProcessChangeBatch(resolutionPolicy, sourceChanges, changeData, new SyncCallbacks(), sessionStatistics); </strong> return sessionStatistics; }
Thanks for looking at this. Let me know if I'm not sending the right code.
Hank
Monday, March 21, 2011 3:18 PM -
your ConfigureSqlSyncProvider and ConfigureCESyncProvider are provisioning two scopes, however, you are setting the provider.ScopeName to ScopeNameToClient. So when they get added to the collection, their scopenames are both ScopeNameToClient.
- Marked as answer by HankAnzis Monday, March 21, 2011 4:56 PM
Monday, March 21, 2011 4:16 PM -
nope. a provider has only one ScopeName property. you should pass the scope name you want to sync in the ConfigureSqlSyncProvider and ConfigureCESyncProvider and assign it to the Scopename property.Monday, March 21, 2011 4:24 PM
-
I see what you are telling me now. I need to have a separate provider for each scope and call the ones I need for each separate sync.
Thanks JuneT,
Hank
Monday, March 21, 2011 4:56 PM