locked
Sync Framework won't upload pre-existing data RRS feed

  • Question


  • Hi,

    Currently, in the "Database Sync - SQL Server and SQL Server Compact" sample you start with an existing server side database and sync it with one or more local databases (full initialization or snapshot). That works great.

    What I'd like to do it the other way around: where my local database already contains data (before it has been provisioned) and try to sync it (upload only) with an empty server side database. Problem is, all that pre-existing data in the local database won't make it to the server, it seems like invisible to the Sync Framework.

    If a add new data to the local once it has been provisioned, then that new data will sync, but not the pre-existing one.


    Sorry my English.
    Thanks.

    Thursday, February 4, 2010 3:37 PM

Answers

  • You maybe seeing this because the source is sending an update and destination is thinking that the row existed at some point of time, but is now deleted and metadata is cleaned up. You should hook into the events and see if you are seeing the LocalCleanedupDeleteRemoteUpdate conflict getting raised.
    If so, then choose the action of RetryWithForceWrite and see if that resolves your issue.
    This posting is provided AS IS with no warranties, and confers no rights
    Friday, February 12, 2010 6:34 AM

All replies

  • have you tried changing the TableCreationOption to UploadExistingOrCreateNewTable?
    Thursday, February 4, 2010 3:55 PM
  • // Connections
    SqlCeConnection clientSqlCeConn = new SqlCeConnection(@"Data Source=C:\Temp\sync1.sdf;Persist Security Info=false;");
    SqlConnection serverConn = new SqlConnection(@"Data Source=.\SQL2005;Initial Catalog=peer1;Integrated Security = true");
    
    // Provisions the client
    SqlCeSyncScopeProvisioning ceConfig = new SqlCeSyncScopeProvisioning();
    if (!ceConfig.ScopeExists(scopename, clientSqlCeConn))
    {
        DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(scopename);
        scopeDesc.Tables.Add(SqlCeSyncDescriptionBuilder.GetDescriptionForTable("orders", clientSqlCeConn));
        scopeDesc.Tables.Add(SqlCeSyncDescriptionBuilder.GetDescriptionForTable("order_details", clientSqlCeConn));
    
        ceConfig.PopulateFromScopeDescription(scopeDesc);
        ceConfig.SetCreateTableDefault(DbSyncCreationOption.Skip);
        ceConfig.Apply(clientSqlCeConn);
    }
    
    // Provisions the server
    SqlSyncScopeProvisioning serverConfig = new SqlSyncScopeProvisioning();
    if (!serverConfig.ScopeExists(scopename, serverConn))
    {
        // FIXME: Not sure if I should get the ScopeDescription from the client.
        DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(scopename);
        scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("orders", serverConn));
        scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("order_details", serverConn));             
    
        serverConfig.PopulateFromScopeDescription(scopeDesc);
        serverConfig.SetCreateTableDefault(DbSyncCreationOption.Skip);
        serverConfig.Apply(serverConn);
    }
    
    // Providers
    SqlCeSyncProvider localProvider = new SqlCeSyncProvider(scopename, clientSqlCeConn);
    SqlSyncProvider serverProvider = new SqlSyncProvider(scopename, serverConn);
    
    // Synchronize       
    SyncOrchestrator orchestrator = new SyncOrchestrator { 
        LocalProvider = localProvider,
        RemoteProvider = serverProvider, 
        Direction = SyncDirectionOrder.DownloadAndUpload
    };
    
    SyncOperationStatistics stats = orchestrator.Synchronize();
    ShowStatistics(stats);
    Console.Read();
    

    AFAIK, in order to use TableCreationOption you have to use SyncTable and SyncAgent, but the code in the sample above uses DbSyncTableDescriptions and SyncOrchestrator.

    I have to admit that i'm still kinda confused with a lot of classes that seems to do the same things (SyncAgent and SyncOrchestrator, for the matter) but in diferents ways.




    Thank you. 
     

               
    

     




    • Edited by maelcumx Friday, February 12, 2010 11:23 AM
    Thursday, February 4, 2010 4:19 PM
  • Hi,

    Indeed, the UploadExistingOrCreateNewTable is for the Offline Scenario providers, a different breed of providers than the Collaboration providers, the ones you are using. It took me quite some time too to make the distinction.

    Unfortunately there does not seem to be an 'out-of-the-box' solution for your issue, as the SqlCeSyncScopeProvisioning class does not support the SetPopulateTrackingTableDefault method. It is only available on the SqlSyncScopeProvisioning class (note: no CE in the name).

    I guess you could use SQL Profiler to look at the sql statements that are being run on a test SQL Server database and convert these into custom code that you can then run on your CE database (client).

    I would think, its 'just' a matter of populating the metadata tables.

    HTH,
    Rudi

    Friday, February 5, 2010 2:32 PM
  • try checking the tables with a suffix of _tracking in the client database. Do you really want to setup Collaboration type of sync?
    Friday, February 5, 2010 3:58 PM
  • Good point ;-)

    Since your scenario seems to involve a client SqlCe database that only needs to sync to a SQL Server database, the 'Offline Scenario' provider might be a better fit for your needs.

    (Also, you can bootstrap your solution by using the 'Local Database Cache' item template in Visual Studio 2008)
    Friday, February 5, 2010 4:13 PM
  • You could use the v2 collaboration providers and still be able to achieve the results.
    After provisioning the database, dummy update the rows (update table1 set column1=column1). This will mark all data as new and then be able to send across.
    We are actually trying to get away from the offline scenario providers because those abilities are pretty much available and handled by the new collaboration providers and they offer more feature sets.
    This posting is provided AS IS with no warranties, and confers no rights
    Monday, February 8, 2010 12:00 AM

  • Thank you all for the clarification.

    I've tried Mahesh approach of dummy updating the client database right after being provioned and now, as you can see from this screenshot, data is been sent across to the server. Sadly, i've noticed data is only been inserted in the "_tracking" tables, and find out the problem might be rows are getting inserted with the column "sync_row_is_tombstone" set to 1 (I think that means DELETED).

    I've uploaded a simple console project, should someone like to have a look:
    http://cid-b97b2a41b5c58deb.skydrive.live.com/self.aspx/P%c3%bablico/SyncTest.zip


    Thank you.

    Monday, February 8, 2010 8:22 AM
  • You maybe seeing this because the source is sending an update and destination is thinking that the row existed at some point of time, but is now deleted and metadata is cleaned up. You should hook into the events and see if you are seeing the LocalCleanedupDeleteRemoteUpdate conflict getting raised.
    If so, then choose the action of RetryWithForceWrite and see if that resolves your issue.
    This posting is provided AS IS with no warranties, and confers no rights
    Friday, February 12, 2010 6:34 AM
  • Thank you, that did it!

    May I ask why is this happening if the server database was empty?

    I'm pasting this snippet should someone else hit this post looking for an answer:

    SqlCeSyncProvider localProvider = new SqlCeSyncProvider(scopename, clientSqlCeConn);
    SqlSyncProvider serverProvider = new SqlSyncProvider(scopename, serverConn);
    serverProvider.ApplyChangeFailed += (o, e) => {
       if (e.Conflict.Type == DbConflictType.LocalCleanedupDeleteRemoteUpdate)
       {
          e.Action = ApplyAction.RetryWithForceWrite;
       }
    };






    Friday, February 12, 2010 11:17 AM
  • The reason for this is server is empty and client is sending this row for the first time. However since this item is sent as an update (because of dummy updates), the server now sees it as an update. When it tries to apply the update, it cannot find the row. It then thinks that the row existed at some point of time, it was then deleted and the metadata cleaned up. So it is treated as a conflict between server (local) delete and client (remote) update.
    Since the default resolution is local wins, delete would win.
    When you now changed the resolution to RetryWithForceWrite, it is remote wins which means the client update wins and will get applied on the server.
    This posting is provided AS IS with no warranties, and confers no rights
    Sunday, February 14, 2010 7:17 AM