How to: Detect Updating Conflicts
During data update operations, especially in shared environments, you might want to determine which fields have changed or what the original or the current values are in changed fields. Visual FoxPro buffering and the GETFLDSTATE( ), GETNEXTMODIFIED( ), OLDVAL( ) and CURVAL( ) functions, enable you to determine which field has changed, find the changed data, and compare the current, original, and edited values so you can decide how to handle an error or conflict.
To detect a change in a field
- After an update operation, use the GETFLDSTATE( ) function.
GETFLDSTATE( ) works on unbuffered data; however, this function is even more effective when you've enabled record buffering. For instance, use GETFLDSTATE( ) in the code of a Skip button on a form. When you move the record pointer, Visual FoxPro checks the status of all fields in the record as in the following example:
lModified = .F.
FOR nFieldNum = 1 TO FCOUNT( ) && Check all fields
if GETFLDSTATE(nFieldNum) = 2 && Modified
lModified = .T.
EXIT && Insert update/Save routine here.
ENDIF && See the next example
ENDFOR
To detect and locate a changed record in buffered data
- Use the GETNEXTMODIFIED( ) function.
GETNEXTMODIFIED( ), with zero as a parameter, finds the first modified record. If another user makes changes to the buffered table, any changes encountered by a TABLEUPDATE( ) command in your buffer will cause conflicts. You can evaluate the conflicting values and resolve them using the CURVAL( ), OLDVAL( ), and MESSAGEBOX( ) functions. CURVAL( ) returns the current value of the record on disk, while OLDVAL( ) returns the value of the record at the time it was buffered.
To determine the original value of a buffered field
- Use the OLDVAL( ) function.
OLDVAL( ) returns the value of a buffered field.
To determine the current value of a buffered field on disk
- Use the CURVAL( ) function.
CURVAL( ) returns the current value on disk of a buffered field before any edits were performed.
You can create an error-handling procedure that compares the current and original values, enabling you to determine whether to commit the current change or to accept an earlier change to data in a shared environment.
The following example uses GETNEXTMODIFIED( ), CURVAL( ), and OLDVAL( ) to provide the user with an informed choice in an update operation. This example continues from detection of the first modified record and might be contained in an Update or Save button on a form.
Click Event Code for an Update or Save Button
Code |
Comment |
---|---|
nCurRec = GETNEXTMODIFIED(nCurRec) DO WHILE nCurRec <> 0 GO nCurRec RLOCK( ) |
Loop through buffer. Lock the modified record. |
FOR nField = 1 TO FCOUNT(cAlias) cField = FIELD(nField) IF OLDVAL(cField) <> CURVAL(cField) nResult = MESSAGEBOX("Data was ; changed by another user. ; Keep changes?", 4+48+0, ; "Modified Record") |
Look for conflict. Compare the original value to the current value on the disk, and then ask the user what to do about the conflict. |
IF nResult = 7 TABLEREVERT(.F.) UNLOCK RECORD nCurRec ENDIF ENDIF ENDFOR nCurRec = GETNEXTMODIFIED(nCurRec) ENDDO |
If the user selects "No," revert this record, and then remove the lock. Find the next modified record. |
TABLEUPDATE(.T., .T.) |
Force update to all records. |
You can use the CompareMemo property to control when memo fields are used to detect update conflicts. This view and cursor property determines whether memo fields (types M or G) are included in the update WHERE clause. The default setting, True (.T.), means that memo fields are included in the WHERE clause. If you set this property to False (.F), memo fields don't participate in the update WHERE clause, regardless of the settings of UpdateType.
Optimistic conflict detection on Memo fields is disabled when CompareMemo is set to False. For conflict detection on memo values, set CompareMemo to True (.T.).
See Also
Concepts
Managing Conflicts When Updating Data
Managing Updates by Using Views