|
The error 'Row changed between retrieve and update.' can be quite common and very annoying.
Also Setting the 'Update Properties' of the datawindow to use where clause based on 'Key Columns' instead of 'Key and Updateable Columns' will reduce the chances of the error. Unfortunately this does not always fit your project requirements. To try to resolve this problem I have written some code to do two things.
It uses a datastore to keep a copy of the problem row and reselects the data from the database. Each updateable column is checked with the original datawindow value. Differences are reset and the columns are shown in a new error message. The sample code uses my datastore object. See A Datastore that Destroys Itself. //---------------------------------------------------------------------------
// Event Name : dberror for ua_dw_std
// Purpose : Shows Row retreive error columns
// Sets : None
//---------------------------------------------------------------------------
string ls_col_name, ls_col_type, ls_column_id
Long ll_index, ll_col_count
string ls_update, ls_changed_columns
boolean lb_changed
string ls_db_error_description
// Row changed between retrieve and update
IF sqldbcode = -3 THEN
IF IsValid(this) THEN
nvo_datastore lnvo_datastore
lnvo_datastore.ds.DataObject = this.DataObject
IF lnvo_datastore.ds.SetTransObject(SQLCA) = 1 THEN
IF this.RowsCopy ( row, row, Primary!, lnvo_datastore.ds, 1, &
Primary!) = -1 THEN
MessageBox("Database Error", "row cannot be copied")
END IF
IF lnvo_datastore.ds.ReSelectRow(1) = -1 THEN
ls_db_error_description = "The current datawindow has" + &
" become out of sync with the database.~r~n" + &
"Data could not be re-retrieved.~r~n" + &
"You should close this window and try again."
MessageBox("Database Error", ls_db_error_description)
ELSE
ls_changed_columns = ""
// Traverse dw's columns making each validation error message
// more user-friendly.
ll_col_count = Long(Describe("Datawindow.Column.Count"))
FOR ll_index=1 TO ll_col_count
ls_column_id = "#" + String(ll_index)
ls_update = Describe(ls_column_id + ".Update")
IF ls_update = "No" THEN
CONTINUE
END IF
// Get Column Details
ls_col_name = Describe(ls_column_id + ".Name")
ls_col_type = Describe(ls_column_id + ".ColType")
lb_changed = FALSE
// Reset the data in the original Datawindow if it has changed.
CHOOSE CASE Upper(Left(ls_col_type, 5))
CASE 'CHAR('
string ls_one, ls_two
IF this.GetItemString(row, ll_index, Primary!, TRUE) <> &
lnvo_datastore.ds.GetItemString(1, ll_index) THEN
lb_changed = TRUE
this.SetItem(row, ll_index, &
lnvo_datastore.ds.GetItemString(1, ll_index))
END IF
CASE 'DATE'
IF this.GetItemDate(row, ll_index, Primary!, TRUE) <> &
lnvo_datastore.ds.GetItemDate(1, ll_index) THEN
lb_changed = TRUE
this.SetItem(row, ll_index, &
lnvo_datastore.ds.GetItemDate(1, ll_index))
END IF
CASE 'DATET'
IF this.GetItemDateTime(row, ll_index, Primary!, TRUE) <> &
lnvo_datastore.ds.GetItemDateTime(1, ll_index) THEN
lb_changed = TRUE
this.SetItem(row, ll_index, &
lnvo_datastore.ds.GetItemDateTime(1, ll_index))
END IF
CASE 'DECIM', 'NUMBE'
IF this.GetItemNumber(row, ll_index, Primary!, TRUE) <> &
lnvo_datastore.ds.GetItemNumber(1, ll_index) THEN
lb_changed = TRUE
this.SetItem(row, ll_index, &
lnvo_datastore.ds.GetItemNumber(1, ll_index))
END IF
CASE 'TIME', 'TIMES'
IF this.GetItemTime(row, ll_index, Primary!, TRUE) <> &
lnvo_datastore.ds.GetItemTime(1, ll_index) THEN
lb_changed = TRUE
this.SetItem(row, ll_index, &
lnvo_datastore.ds.GetItemTime(1, ll_index))
END IF
END CHOOSE
IF lb_changed THEN
IF Len(ls_changed_columns) > 0 THEN
ls_changed_columns += ", "
END IF
ls_changed_columns += ls_col_name
// Set the flag to say that it has not been changed.
this.SetItemStatus(row,ls_col_name, Primary!, NotModified!)
END IF
NEXT
IF Len(ls_changed_columns) > 0 THEN
ls_db_error_description = &
"The current datawindow has become out of sync with the database.~r~n" + &
"These column(s) have been reset~r~n" + ls_changed_columns + &
"~r~nYou may need to re-enter your changes and save again."
MessageBox("Database Error",ls_db_error_description, Exclamation!)
// Stop the Powerbuilder error message
RETURN 1
END IF
END IF
END IF
END IF
END IF
|