What is proper way to handle concurrent updates with lmOptimistic?
Posted: Wed 08 Jul 2020 14:28
We are using UniDAC with Embarcadero C++Builder 10.3.3. Our code works but it depends on detecting literal exception message text "Record was changed by another user". If this text changes in a future release then our application will fail and we will not know unless we test for it or our client reports an issue. What is the proper way to handle this situation?
There can be multiple instances of our application which can concurrently updated the same record. When this happens one instance succeeds and the others fail by throwing an exception. After some experimenting with the available handlers and exceptions we determined that detecting the message string in the catch( EDatabaseError& e ) worked. What is the proper way to do this that will work even if the exception message text changes?
Here is the VCL .dfm file text for one of the tables and its data source:
Note the default settings include:
LockMode = lmOptimistic
RefreshOptions empty (i.e. does not include roAfterUpdate)
Here is the relevant code which is meeting client requirements:
There can be multiple instances of our application which can concurrently updated the same record. When this happens one instance succeeds and the others fail by throwing an exception. After some experimenting with the available handlers and exceptions we determined that detecting the message string in the catch( EDatabaseError& e ) worked. What is the proper way to do this that will work even if the exception message text changes?
Here is the VCL .dfm file text for one of the tables and its data source:
Code: Select all
object UniTblManufacturer: TUniTable
TableName = 'Manufacturer'
Connection = UniConICS2
Left = 35
Top = 71
object UniTblManufacturerManufacturerID: TIntegerField
AutoGenerateValue = arAutoInc
FieldName = 'ManufacturerID'
ReadOnly = True
Required = True
Visible = False
end
object UniTblManufacturerManufacturerName: TStringField
DisplayLabel = 'Manufacturer Name'
FieldName = 'ManufacturerName'
Required = True
Size = 30
end
end
object UniManufacturersSource: TUniDataSource
DataSet = UniTblManufacturer
Left = 147
Top = 71
end
LockMode = lmOptimistic
RefreshOptions empty (i.e. does not include roAfterUpdate)
Here is the relevant code which is meeting client requirements:
Code: Select all
bool bUpdateConflict = false;
try
{
UniTblManufacturer->Post();
}
catch( EUniError& e )
{
sErrMsg = e.Message;
}
catch( EDatabaseError& e )
{
if( e.Message.Compare( "Record was changed by another user" ) == 0 )
bUpdateConflict = true;
sErrMsg = e.Message;
}
catch(...)
{
sErrMsg = String( "Unspecified exception." );
}
if( bUpdateConflict )
// Handle the update conflict:
// Warn user and display the current field values.
// Ask user to review field values, reenter desired changes, and try update again.