4D v17 introduces ORDA, a major evolution in 4D which is opening a world of new possibilities for 4D developers. One of the benefits of using ORDA is related to record locking, because ORDA offers a choice between optimistic and pessimistic locking. After having introduced the ORDA locking mechanisms, we continue the ORDA series so you can discover how to work efficiently with optimistic locking with ORDA.
Example: optimistic locking with ORDA
Optimistic locking in a few words
In optimistic locking mode, records are not explicitly locked before they’re updated.
Optimistic locking relies on the stamp of the records. Each record has an internal stamp that is automatically incremented every time a record is saved in the database. If a record has been updated since you loaded an entity, the save(), drop(), and lock() methods will return a specific status code indicating that the stamp has changed.
RECORDs AND ENTITies
Just as a reminder, a record is the physical record in the database which is accessed through an entity. An entity is a reference on a record (see Entity section in the glossary). Records are locked and unlocked through entities.
Code example
In the example below, we handle two scenarios where the save() method fails.
C_OBJECT($status;$employee)
// Get the first employee whose last name is "Smith"
$employee:=ds.Employee.query("lastName=:1";"Smith").first()
If ($employee#Null)
$employee.lastName:="Wates" // Update employee's last name
$status:=$employee.save() // Save employee
if (Not($status.success)) // The save action fails
Case of
// The record has been updated in database since the entity was loaded
: ($status.status=dk status stamp has changed)
alert("Someone has updated the record since you have loaded it")
//The record is locked by another process
: ($status.status=dk status locked)
alert("Someone has locked the record")
End case
end if
end if
CASE 1: ENTITY HAS CHANGED
If the record has been updated in the database since you loaded the entity, the returned $status object will be as follows:
{ "status": 2, "statusText": "Stamp has changed", "success": false }
CASE 2: ENTITY is already locked
If the record in the database is already locked by another process, the returned $status object will be as follows:
{ "status": 3, "statusText": "Already Locked", "lockKind": 1, "lockKindText": "Locked By Record", "lockInfo": { "task_id": 5, "user_name": "Mary Smith", "user4d_id": 1, "host_name": "iMac27-Program6", "task_name": "P_10", "client_version": -1610541312 }, "success": false }
COMMON scenarios
To accompany the save() method, ORDA provides a very useful option: dk auto merge.
dk auto merge attempts to automatically merge the updates done in an entity loaded in memory with those done on the record in the database. Hoever, it may fail if you updated the same properties in your loaded entity as another user updated in the database record.
Therefore, we offer two options to manage this.
1- OVERRIDE THE UPDATES DONE IN the DATABASE
In the example below, the save() method with dk auto merge fails.
We are certain that we want to override the updates done in the database by another process.
We manage this case by:
1- Before saving, we use the clone() method. This creates a new reference on our updated entity. It’s useful to make a copy of an entity to reuse it later.
When the save() method fails, we:
2- Use the reload() method to reload our entity from the database record so we can get an up-to-date stamp.
3- Using the cloned entity, we reapply our updates.
4- We save the entity again and test the returned status.
C_OBJECT($status;$employee;$clonedEmployee)
// Get the first employee whose last name is "Smith"
$employee:=ds.Employee.query("lastName=:1";"Smith@").first()
If ($employee#Null)
// Update the last name
$employee.lastName:="Dunaway"
// Clone the loaded entity
$clonedEmployee:=$employee.clone()
// Save the entity with auto merge option
$status:=$employee.save(dk auto merge)
// The save action fails
While (Not($status.success))
// The auto merge failed
If ($status.status=dk status automerge failed)
// Reload the entity. The stamp will be updated
$employee.reload()
// Reapply the update on last name
$employee.lastName:=$clonedEmployee.lastName
// Save the entity
$status:=$employee.save(dk auto merge)
End if
End while
End if
2- BUILD A USER INTERFACE TO MANUALLY MANAGE CONFLICTS BETWEEN AN ENTITies and RECORDs
ORDA provides useful methods to help you build an interface allowing users to choose between their updates and other done at the same time.
Here’s a quick overview of these methods. Take a look at the documentation for more details.
- touchedAttributes() method: returns attributes which have been accessed since you loaded or saved an entity.
- diff() method: compares two entities
In the provided HDI, you’ll see how to build such an interface.