Handling conflicts for direct uploads

When a MobiLink client sends an updated row to the MobiLink server, it includes not only the updated values (the post-image or new row), but also a copy of the old row values (the pre-image or old row) obtained in the last synchronization with the MobiLink server. When the pre-image row does not match the current values in your central data source, a conflict is detected.

SQL-based conflict resolution

For SQL-based uploads, the MobiLink consolidated database is your central data source and MobiLink provides special events for conflict detection and resolution.

See Handling conflicts.

Conflict resolution with direct row handling

For direct uploads, you can access new and old rows programmatically for conflict detection and resolution.

UpdateResultSet (returned by the UploadedTableData.getUpdates method) extends standard Java or .NET result sets to include special methods for handling conflicts. setNewRowValues sets UpdateResultSet to return new updated values from a remote client (the default mode). setOldRowValues sets UpdateResultSet to return old row values.

Detecting conflicts with direct row handling

By using the UpdateResultSet method .setOldRowValues, you get the values of a row on the remote before it was changed. You compare the row values that are returned to the existing row values in your data source. If the rows you compare are not equal, then a conflict exists.

Resolving conflicts with direct row handling

Once you have detected a conflict during an upload, you can use custom business logic to resolve the conflict. The resolution is handled by your Java or .NET code.

Example

Suppose you track inventory in an XML document and want to use it as your central data source. User1 uses one of your remote databases called Remote1. User2 uses another remote database called Remote2.

Your XML document, User1, and User2 all start with an inventory of ten items. User1 sells three items and updates the Remote1 inventory value to seven items. User2 sells four items and updates the Remote2 inventory to six items. When Remote1 synchronizes, the central database is updated to seven items. When Remote2 synchronizes, a conflict is detected because the value of the inventory is no longer ten items. To resolve this conflict programmatically, you need three row values:

  • The current value in the central data source.
  • The new row value that Remote2 uploaded.
  • The old row value that Remote2 obtained during the last synchronization.

In this case, the business logic would use the following formula to calculate the new inventory value and resolve the conflict:

current data source - (old remote - new remote)
-> 7 - (10-6) = 3

The following procedures for Java and .NET demonstrate how you can resolve this conflict for direct uploads, using the following table as an example:

CREATE TABLE remoteOrders
(
    pk integer primary key not null,
    inventory integer not null
);

To handle direct conflicts (Java)

  1. Register a Java or .NET method for the handle_UploadData connection event.

    See handle_UploadData connection event.

    For example, the following stored procedure call registers a Java method called HandleUpload for the handle_UploadData connection event when synchronizing the script version ver1. You run this stored procedure against your MobiLink consolidated database.

    call ml_add_java_connection_script( 'ver1',
       'handle_UploadData',
       'OrderProcessor.HandleUpload' )

    For more information about registering methods for synchronization events, see:

  2. Obtain an UpdateResultSet for a table in the upload.

    The OrderProcessor.HandleUpload method obtains an UpdateResultSet for the remoteOrders table:

    // method for handle_UploadData event
     public void HandleUpload( UploadData u_data )
     {
     
        // Get UploadedTableData for the remoteOrders table.
          UploadedTableData u_table = u_data.getUploadedTableByName("remoteOrders");
       
        // Get an UpdateResultSet for the remoteOrders table.
        UpdateResultSet update_rs = u_table.getUpdates();
       
        // (Continued...)
  3. For each update, get the current values in your central data source.

    In this example, the UpdateResultSet getInt method returns an integer value for the primary key column (the first column). You can implement and then use the getMyCentralData method to get data from your central data source.

    while( update_rs.next() )
    {
       // Get central data source values.
    
       // Get the primary key value.
       int pk_value = update_rs.getInt(1);
    
       // Get central data source values.
       int central_value = getMyCentralData(pk_value);
    
       // (Continued...)
  4. For each update, get the old and new values uploaded by the MobiLink client.

    The example uses the UpdateResultSet setOldRowValues and UpdateResultSet setNewRowValues for old and new values, respectively.

      // Set mode for old row values.
      update_rs.setOldRowValues();
    
      // Get the _old_ stored value on the remote.
      int old_value = update_rs.getInt(2);
    
      // Set mode for new row values.
      update_rs.setNewRowValues();
    
      // Get the _new_ updated value on the remote.
      int new_value = update_rs.getInt(2);
    
      // (Continued...)
  5. For each update, check for conflicts.

    A conflict occurs when the old row value does not match the current value in the central data source. To resolve the conflict, a resolved value is calculated using business logic. If no conflict occurs, the central data source is updated with the new remote value. You can implement and then use the setMyCentralData method to perform the update.

      // Check if there is a conflict.
    
      if(old_value == central_value)
      {
        // No conflict.
        setMyCentralData(pk_value, new_value);
       
      }
      else
      {
        // Handle the conflict.
        int inventory = old_value - new_value;
        int resolved_value = central_value - inventory;
      
        setMyCentralData(pk_value, resolved_value);
    
      }
    }

To handle direct conflicts (.NET)

  1. Register a method for the handle_UploadData connection event.

    For example, the following stored procedure call registers a .NET method called HandleUpload for the handle_UploadData connection event when synchronizing the script version ver1. You run this stored procedure against your MobiLink consolidated database.

    call ml_add_dnet_connection_script( 'ver1',
       'handle_UploadData',
       'MyScripts.OrderProcessor.HandleUpload' )

    For more information about registering methods for synchronization events, see:

  2. Obtain an UpdateDataReader for a table in the upload.

    The MyScripts.OrderProcessor.HandleUpload method obtains an UpdateResultSet for the remoteOrders table:

    // method for handle_UploadData event
     public void HandleUpload( UploadData u_data )
     {
     
        // Get UploadedTableData for the remoteOrders table.
          UploadedTableData u_table = u_data.GetUploadedTableByName("remoteOrders");
       
        // Get an UpdateDataReader for the remoteOrders table.
        UpdateDataReader update_dr = u_table.GetUpdates();
       
        // (Continued...)
  3. For each update, get the current values in your central data source.

    In this example, the UpdateDataReader GetInt32 method returns an integer value for the primary key column (the first column). You can implement and then use the getMyCentralData method to get data from your central data source.

    while( update_dr.Read() )
    {
       // Get central data source values.
    
       // Get the primary key value.
       int pk_value = update_dr.GetInt32(0);
    
       // Get central data source values.
       int central_value = getMyCentralData(pk_value);
    
       // (Continued...)
  4. For each update, get the old and new values uploaded by the MobiLink client.

    The example uses the UpdateResultSet setOldRowValues and UpdateResultSet setNewRowValues for old and new values, respectively.

      // Set mode for old row values.
      update_dr.SetOldRowValues();
    
      // Get an _old_ value.
      int old_value = update_dr.GetInt32(1);
    
      // Set mode for new row values.
      update_dr.SetNewRowValues();
    
      // Get the _new_ updated value.
      int new_value = update_dr.GetInt32(1);
    
      // (Continued...)
  5. For each update, check for conflicts.

    A conflict occurs when the old row value does not match the current value in the central data source. To resolve the conflict, a resolved value is calculated using business logic. If no conflict occurs, the central data source is updated with the new remote value. You can implement and then use the setMyCentralData method to perform the update.

      // Check if there is a conflict.
    
      if(old_value == central_value)
      {
        // No conflict.
        setMyCentralData(pk_value, new_value);
       
      }
      else
      {
        // Handle the conflict.
        int inventory = old_value - new_value;
        int resolved_value = central_value - inventory;
      
        setMyCentralData(pk_value, resolved_value);
    
      }
    }