Share via


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

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

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

OLDVAL( ) returns the value of a buffered field.

To determine the current value of a buffered field on disk

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

Reference

GETFLDSTATE( ) Function

GETNEXTMODIFIED( ) Function

Other Resources

Programming for Shared Access