Because the ProDataSet with its independent FILL and save operations necessarily relies on an optimistic locking strategy, you need to consider what behavior you want in the event of a conflict with another change made since the ProDataSet was filled from its Data-Source. The AVM supports a number of options to give you automated support for almost any circumstance.
The first decision you need to make is whether a conflict with another change should be overwritten by the current ProDataSet's change, or rejected when the AVM detects a conflict.
In some cases, you might not care whether a record has been changed by another user since it was read. Although this is certainly not typical or recommended, for some non-transactional tables that contain fields that can safely be changed independently of one another (possibly address information, for example), you might not want to reject a change if the record has been changed elsewhere. There is a PREFER-DATASET logical attribute for the Data-Source to support this option. The attribute is false by default. If PREFER-DATASET is false for the table's Data-Source, then the AVM makes the comparison between the before-table row in the database and the corresponding Data-Source fields before applying the change. If there is any conflict, then the change is rejected and the ERROR attribute is set. If PREFER-DATASET is true, this check is not made. The ProDataSet row changes are written to the Data-Source without regard to any other changes made to the same row. As noted previously, only the database fields that are present in the ProDataSet temp-table, either implicitly or by being mapped to a field with a different name, can be compared.
You also may want to apply changes and resolve conflicts on a field by field basis. This is somewhat more expensive than either applying or rejecting all changes, but minimizes the overwriting of either your changes or another user's changes when a conflict occurs. There is a MERGE-BY-FIELD logical attribute on the Data-Source to specify this preference. This attribute is true by default. It gives you the ability to define whether a change is wholly rejected if there are any conflicting changes, even to different fields than the ones the ProDataSet is changing.
If MERGE-BY-FIELD is false and if another user has changed a record, the ProDataSet changes are either entirely accepted or entirely rejected, depending on the setting of PREFER-DATASET. If MERGE-BY-FIELD is true, then the AVM "blends" the two sets of changes where possible, if they are to different fields. If it is true, then changes are applied field-by-field only for modified fields, and there is no conflict unless the same field has been modified both by the current update and by another transaction. A logical DATA-SOURCE-MODIFIED attribute on the temp-table buffer is set to true if any field changes by another transaction are detected, regardless of whether they result in a conflict and error or not. Note that it is somewhat slower to have MERGE-BY-FIELD set to true, so it can be set to false to improve performance where a field-by-field check is really not necessary, in addition to cases where it is not wanted because of the application logic.
Here are the details of how changes are applied in the face of these attributes. In this description, "current changes" refers to modifies and deletes that are part of a ProDataSet the procedure is doing a SAVE-ROW-CHANGES on (the "current ProDataSet"). Obviously create operations do not need to check for conflicting field values. "Other changes" refers to changes made to the fields in the same rows by another user or procedure since the current ProDataSet was filled, which will be detectable by comparing the database buffers with the before-tables in the current ProDataSet.
If MERGE-BY-FIELD is false, then these are the actions:
If PREFER-DATASET is true, then the modified or deleted row is updated or deleted without regard to whether there were other changes. In the case of a modify, all fields in the current ProDataSet row are copied to the database buffer, whether they were changed in the current ProDataSet or not. In the case of a delete, the database record is simply deleted.
If PREFER-DATASET is false (the default), then the AVM compares the ProDataSet before-table with the database buffers. If there are any other changes, then the current change is rejected and the AVM sets the ERROR attribute. If the action was a delete, the row is not deleted from the database or the current ProDataSet. The AVM also sets the DATA-SOURCE-MODIFIED attribute on the row. It buffer-copies the entire database buffer back to the current ProDataSet's after-table row, to allow the changes to be seen back on the client.
If MERGE-BY-FIELD is true (the default), then rather than doing a wholesale buffer-copy in one direction or the other, the AVM does a field-by-field compare of the two buffers. In this case:
This is the action if PREFER-DATASET is true:
If the operation is a delete, then the database row is deleted without regard to whether there were other changes.
Otherwise, for a Modify:
If the field has not been changed in the current ProDataSet, then nothing is copied. This means that a change made by another user to a field that was not changed in the current ProDataSet will not be overwritten by the current change.
If the field has been changed in the current ProDataSet, it is copied to the database field. There is no check of whether there were other changes.
These are the actions if PREFER-DATASET is false:
If the operation is a delete, and there are no other changes to the row, then the database record is deleted.
If the operation is a delete, and there are other changes to the row, then the delete fails, the AVM buffer-copies the entire database record into the ProDataSet buffer, and sets the ERROR and DATA-SOURCE-MODIFIED attributes.
Otherwise, for a Modify:
If the field was changed in the current ProDataSet and not by other changes, then it is copied to the database.
If the field was not changed in the current ProDataSet, and also not by other changes, then nothing is copied.
If the field was changed in the current ProDataSet, and by other changes, then the AVM checks whether the other changes are the same as the current ProDataSet change. If this is the case, the AVM sets the ERROR flag. If the changed values are different, the AVM buffer-copies that one field from the database record back into the ProDataSet buffer, and sets the ERROR and DATA-SOURCE-MODIFIED flags. The current ProDataSet changes are not applied to the database, but the field by field comparison continues so that only those fields changed by other changes overwrite the current ProDataSet changes.
If the field was not changed in the current ProDataSet, but was changed by other changes, then the other changes are copied into the ProDataSet buffer, and the AVM sets the DATA-SOURCE-MODIFIED flag. This is not an error, however.
The net result of all this is, when PREFER-DATASET is false and MERGE-BY-FIELD is true, a modified row in the current ProDataSet is rejected in its entirety and causes an error only when one or more of the same fields have been changed by another user. Otherwise changed fields in the current ProDataSet row are successfully written to the database. Changes made by others are copied to the ProDataSet buffer to be returned to the client, and the CHANGED flag is set.
This may all sound complicated, but in effect it means that the AVM "does the right thing" based on whether you want the new change or the old change to take precedence, and whether or not you want to apply changes field by field or as a whole. The following table summarizes the results.