Working with ORDA optimistic locking

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.

Avatar
• Product Owner • Marie-Sophie Landrieu-Yvert has joined the 4D Product team as a Product Owner in 2017. As a Product Owner, she is in charge of writing the user stories then translating it to functional specifications. Her role is also to make sure that the feature implementation delivered is meeting the customer need.Marie-Sophie graduated from the ESIGELEC Engineering School and began her career as an engineer at IBM in 1995. She participated on various projects (maintenance or build projects) and worked as a Cobol developer. Then she worked as an UML designer and Java developer. Lately her main roles were analyzing and writing functional requirements, coordinate business and development teams.