locked
DownloadChangesFailed but no ApplyChangesFailed event? RRS feed

  • Question

  • I am synchronizing SQL Server 2008 and SQL CE 3.5 SP1 (bi-directional).
    It works fine in normal conditions. However, in stress scenarios (few threads using CE for long operations), I occasionally see that SyncAgent.Synhronize() call returns SyncStatistics with DownloadChangesFailed > 0 (actual number depends on the # of rows that are in the changeset). I was hoping that I will get ApplyChangesFailed event but that is not happening. 

    #1 - How do I see details of 'why' DownloadChangesFailed? 
    #2 - How do I rollback that sync call?
    #3 - How can I retry (Assuming that merely calling Synchronize again will actually use the new anchor position as opposed to old one)?

    Thanks,
    Nitesh Ambastha
    Monday, January 11, 2010 3:51 AM

Answers

  • It is ApplyChangeFailed event.  If you did not see it from your client provider, please share the client provider class name and assembly your sync app referenced to.

    The below sample code is just for your reference only, and if the client provider is a [SqlCeClientSyncProvider] object.


    // in your sync app

                    SqlCeClientSyncProvider cp = (SqlCeClientSyncProvider)syncAgent.LocalProvider;
                    cp.ApplyChangeFailed += new EventHandler<ApplyChangeFailedEventArgs>(cp_ApplyChangeFailed);


    // event handler sample

            void cp_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e)
            {
                System.Data.Common.DbCommand command = null;
                System.Data.DataRow dr2 = null;

                System.Data.DataRow dr = e.Conflict.ServerChange.Rows[0];

                Console.WriteLine(e.Conflict.ServerChange.Columns.Count.ToString());
                SyncSession syncSession = e.Session;
                Console.WriteLine(string.Format("ApplyChangeFailed: SyncSession.SessionId = {0}", syncSession.SessionId));

                switch (e.Conflict.ConflictType)
                {
                    case ConflictType.ClientUpdateServerUpdate:
                            Console.WriteLine("We let Server win. So do a ForceWrite.");
                            e.Action = ApplyAction.RetryWithForceWrite;
                        break;

                    case ConflictType.ClientDeleteServerUpdate:
                            // use client's upsert behavior
                            e.Action = ApplyAction.RetryWithForceWrite;
                        break;

                    case ConflictType.ClientInsertServerInsert:
                            // use retry and compensate the client change to make server one going through                      
                            e.Action = ApplyAction.RetryApplyingRow;
                        break;
                }

            }

    Thanks.


    Leo Zhou ------ This posting is provided "AS IS" with no warranties, and confers no rights.
    Tuesday, January 12, 2010 5:58 PM
    Answerer

All replies

  • I assume that you are using Sync Service for ADO.NET.

    1. If you would like to see DownloadChangesFailed event, you need to have an event handler connected to this event from SQL CE client sync provider.  Then in the event handler, you can retrieve the conflict information from
    .Conflict.ConflictType and .Conflict.ErrorMessage of ApplyChangeFailedEventArgs.

    2. You can also use the Retry logic when apply the current row sees a conflict in the DownloadChangesFailed  event handler as
    e.Action = ApplyAction.RetryApplyingRow;
    e.Action = ApplyAction.RetryWithForceWrite;

    3. Also if you like to rollback the change appication transaction, please throw an exception in the DownloadChangesFailed event handler.

    Thanks.
    Leo Zhou ------ This posting is provided "AS IS" with no warranties, and confers no rights.
    Monday, January 11, 2010 6:17 PM
    Answerer
  • Thanks Leo.

    Is there such a thing like DownloadChangesFailedEvent?
    Can you please post a mini sample for this?
    Tuesday, January 12, 2010 10:14 AM
  • It is ApplyChangeFailed event.  If you did not see it from your client provider, please share the client provider class name and assembly your sync app referenced to.

    The below sample code is just for your reference only, and if the client provider is a [SqlCeClientSyncProvider] object.


    // in your sync app

                    SqlCeClientSyncProvider cp = (SqlCeClientSyncProvider)syncAgent.LocalProvider;
                    cp.ApplyChangeFailed += new EventHandler<ApplyChangeFailedEventArgs>(cp_ApplyChangeFailed);


    // event handler sample

            void cp_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e)
            {
                System.Data.Common.DbCommand command = null;
                System.Data.DataRow dr2 = null;

                System.Data.DataRow dr = e.Conflict.ServerChange.Rows[0];

                Console.WriteLine(e.Conflict.ServerChange.Columns.Count.ToString());
                SyncSession syncSession = e.Session;
                Console.WriteLine(string.Format("ApplyChangeFailed: SyncSession.SessionId = {0}", syncSession.SessionId));

                switch (e.Conflict.ConflictType)
                {
                    case ConflictType.ClientUpdateServerUpdate:
                            Console.WriteLine("We let Server win. So do a ForceWrite.");
                            e.Action = ApplyAction.RetryWithForceWrite;
                        break;

                    case ConflictType.ClientDeleteServerUpdate:
                            // use client's upsert behavior
                            e.Action = ApplyAction.RetryWithForceWrite;
                        break;

                    case ConflictType.ClientInsertServerInsert:
                            // use retry and compensate the client change to make server one going through                      
                            e.Action = ApplyAction.RetryApplyingRow;
                        break;
                }

            }

    Thanks.


    Leo Zhou ------ This posting is provided "AS IS" with no warranties, and confers no rights.
    Tuesday, January 12, 2010 5:58 PM
    Answerer
  • Leo,

    Related to original problem --
    Does it mean that Sync does not support following scenario?

    Suppose in my schema I have a table A, which only has one column called 'Color'. I also have a sync filter on this column to sync only 'Red' entries from the server to CE. In the beginning there are two rows on the server  -- 'Red' and 'Green'. At this point if I sync CE with server I will get 'Red' in CE, which is good.
    But later if I update on server the 'Green' to 'Red' and sync CE again, I would expect it to get 'Red' and 'Red'. But I still see only one 'Red' entry in CE which is from older sync.

    Any rationale behind not supporting such scenario.

    Thanks
    Sumit

    Monday, January 25, 2010 7:23 PM