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.
For SQL-based uploads, the MobiLink consolidated database is your central data store and MobiLink provides special events for conflict detection and resolution.
See Handling conflicts.
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.
For example, User1 starts with an inventory of ten items, and then sells three and updates the Remote1 inventory value to seven items. User2 sells four items and updates the Remote2 inventory to six. When Remote1 synchronizes, the central database is updated to seven. When Remote2 synchronizes, a conflict is detected because the value of the inventory is no longer ten. To resolve this conflict programmatically, you need three row values:
The current value in the consolidated database.
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 consolidated - (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, number_sold integer not null )
Register a method for the 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:
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...)
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...)
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 an _old_ value. int old_value = update_rs.getInt(2); // Set mode for new row values. update_rs.setNewRowValues(); // Get the _new_ updated value. int new_value = update_rs.getInt(2); // (Continued...)
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 number_sold = old_value - new_value; int resolved_value = central_value - number_sold; setMyCentralData(pk_value, resolved_value); } }
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:
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...)
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...)
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...)
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 number_sold = old_value - new_value; int resolved_value = central_value - number_sold; setMyCentralData(pk_value, resolved_value); } }