Demo IV: Offline Application – Conflict Handling

It is about time for our offline application to deal with sync conflicts. Conflicts are fact of life in lazy synchronization environments. It is likely that your application users don’t want to deal with conflicts. Therefore you are encouraged to architect your solution in such a way that would make conflicts rare. However, your application is not complete without conflict handling logic. Before I go into more details, let’s define what conflict is:

“A row is said to be in conflict if it was changed on two or more nodes between synchronization requests”

In two node environment, client could make a change to a row R while offline, at the same time a change is made at the server to R. When both ends sync, a conflict is detected. In n-node environment, a conflict could happen by independent changes to R on two or more clients.

Conflict Types

The sync framework detects four types of conflicts:

  • ClientInsertServerInsert also known as PK Collision; occurs when both client and server insert a row with same PK
  • ClientUpdateServerUpdate the most common conflict; occurs when client and server make changes to the same row independently
  • ClientUpdateServerDelete occurs when the client updates a row and the server independently deletes the same row
  • ClientDeleteServerUpdate occurs when the client deletes a row and the server independently updates the same row

Note: The use of “Server” term in the conflict type names above does not necessarily mean that the changes were authored on the server. In fact, the server could be a passive node that just collects and distributes changes. However, from the synchronizing client point of view, the change appears to have happened on the server thus the naming.

Conflict Detection and Resolution

The sync framework fires ApplyChangeFailedEvent from both client and server sync providers when it detects a conflict. In this demo application, I registered to receive conflict events from both client and server providers. Each conflict is then presented to the user with possible conflict resolution options:

  1. Ignore the conflict and continue
  2. Retry applying the row, without changing to the datarow the retry will fail causing the event to be raised again. The demo does not allow you to edit the datarow though.
  3. Retry with Force Write has a built in support in the ClientSyncProvider, on the server side, you need to add support in your sync adapter commands and the demo show an example for update-update conflict.
  4. Abort the Sync by throwing an exception; all changes will be rolled back and re-synced in the next sync session.

SyncAdapter Conflict Commands

There are two commands that we did not explore in the previous demos:

  • SelectConflictUpdatedRowsCommand this command finds conflicting rows in the base table. The sync runtime executes this command if insert, update or delete command failed (i.e. returned 0 row count)
  • SelectConflictDeletedRowsCommand this command finds conflicting rows in the tombstone table. The sync runtime executes this command if the conflicting row was not found in the base table. This is how ClientUpdateServerDelete conflict is detected.

Demo Enhancements

  • I’ve added few more buttons to generate random conflicts
  • Also I changed the tombstone tables to accept more than one delete for the same PK. (there were questions about that in the forum)

How to install OfflineAppDemo application?

  1. Fire SQL server and load demo.sql file
  2. Execute the script untill the "test sample" marker
  3. Load server_procs.sql file and execute it to install server procs
  4. Load VS solution (OfflineAppDemo-Conflicts Project) 
  5. Build the project 
  6. You are ready to go

Download Now
Feedback: Visit Sync Services Forum


Update: Just to let you know, I left Microsoft to start a new company, Raveable Hotel Reviews. See examples: Top 10 Hotels in Myrtle Beach, Best Hotels in NYC,Romantic Hotels in Seattle, Kid Friendly Hotels in Orlando and Top 10 Hotels in San Diego. Your feedback is welcome on, raveable blog.

Comments (8)

  1. rogerj says:

    Hi, Rafik,

    Thanks for the series of demos.

    Your demo.sql script for Demo IV needs a minor fixup: tombstone tables aren’t created. Change shop.. to pub.. for the two tombstone tables with composite primary keys.

    Demo app itself runs fine for me.


  2. MSDN Archive says:

    Thanks Roger,

    Just updated the demo.sql and posted a new (v1.1) package.


  3. rogerj says:

    Hi, Rafik,

    Minor wart: The text box for Server Database actions shows # rows inserted for updates and deletes, as well as inserts. Client text box is OK.

    Displaying the number of actions is a nice addition.

    Illustrated post about the app will be on in a few minutes.


  4. MSDN Archive says:

    Updated it to v1.2!

    I really appreciate your comments; it is helping me out improving the demo



  5. citytours says:

    Hi Rafik,

    I posted this question to the newsgroup and realized this is probably a better place for the question.  

    I have to admit that I am new to all of this so I apologize if this is obvious.  I can not tell from this if you have access to the "before" value of the update.  For some conflict resolution I want to be able to handle the update based on the value it was previously.  Can you tell me if that is possible?

    By the way, this demo looks really good.

  6. MSDN Archive says:


    I saw the question. It is a very interesting point. I will reply to you shortly on the forum.


    Rafik Robeal

  7. RajeshPR says:

    Hi RAFIK

    That was a great demo, actually I am using ADO.Net sync in my new project was waiting to understand how conflicts would be handled.

    Can you also let me know as to where to I add code in the sample application which could show me handling force write in a insert-insert conflict.

    I mean forcing client changes to the server rows.

  8. MSDN Archive says:

    The code has to go into your insert command on the sync adapter object. The command or stored procedure has to check if force write flag is set and if so it does an update statement and not an insert since the row already exists.


Skip to main content