Support Topics Documentation Slack YouTube Blog

How to get the object from OpResultValueReference?

I am trying to use transaction to retrieve an object from Backendless database.
I have read the docs but still can’t figure out how to get/retrieve the data object from the opresult/opresultvaluereference.

Thank you.

OpResulrValueReference is used to reference a value in another operation. You do not retrieve it, you simply use it as a pointer.

Okay, that means i should rephrase/change the question.
If I have the following code:
val retrieveDataOpResult = unitOfWork.find("Test", dataQueryBuilder)

What method should be used to get the object from that operation?
I would like to get some attributes/properties value.
There is a method called getPropName() but I am not really sure of it.

Thanks.

Is it all you need to do - retrieve data from the database?

Since transaction provides some isolation level, it may be safer to work with that. I want to do some sensitive operations where the data must remain consistent to any clients/app instances connected to the database.

While retrieving the data object simply do, but I want to make sure that the data is consistent.
Using transaction will do.

I would like to retrieve an attribute/property from the object retrieved through a transaction, calculate the value, and then update it. The updated value must be calculated using the value of fetched object which is added/reduced with the value within the app.

If the value you calculate is done on the client side, then transactions will not work here. A transaction has multiple operations, all of which are executed in a batch on the server.

Never mind, looks like I figure something out.

Maybe you misunderstand what I am trying to achieve.
I would like to update a property of an object, which is calculated between the value of respective property within the fetched object and the value in the client (added, deducted, multiplied, etc.)
After that, I apply that new value using a transaction.

Does that makes sense? It should and can be done with transaction. I am aware that transactions are executed in a batch on the server, but I am not talking about that. The app calls a request for transaction, which should be no problem.

Will reply back if I figure something out.
Thanks, Mark

We’re adding an ability to do some interim operations on the value(s) retrieved in a transaction before it is updated in the same transaction. However, that functionality has not been released yet.

Regards,
Mark

Any workaround you can suggest while we wait for the feature to be released?

By the way, what does this mean?
The “Repeatable read” is the default isolation level in the Backendless Database.

I got it from the transaction isolation docs.
Does this mean that any queries run on backendless database are using Repeatable read isolation level by default even if we don’t use Unit of Work API?

As for the workaround, what kind of calculation do you need to perform on the value?

About the isolation level, when you perform a single API call, the transaction isolation level is irrelevant because transaction isolation level makes sense only when you have two or more operations in a transaction.

So that means that even using normal object retrieval API without transaction, any returned/fetched data objects will maintain consistency?

My use case is: I would like to fetch an object, retrieve specific value, add / deduct it with the value in client side, then apply the update. That’s the calculation I want to perform.
Since for now there’s no way for us to retrieve that “specific value” from transaction, I need to perform some workaround since this has been a requirement and we are progressing significantly with Backendless. The transaction isolation API is one of many reasons we use this awesome backend platform.

How about I retrieve the data using a normal object retrieval API, fetch the value of specific property/attribute I need, and then perform the update using transaction? This must be isolated since I don’t want other users/clients messing up when one still working with it. How’s about that?

So that means that even using normal object retrieval API without transaction, any returned/fetched data objects will maintain consistency?

Without transactions, this is how it works now:

  1. User A fetches object X
  2. User A makes changes to object X
  3. User B changes object X in the database
  4. User A saved changes to object X

End result: changes made by User B are lost. Transaction isolation applies only to the Unit of work API.
If your goal is to prevent other users from changing data fetched by others, is to implement some kind of record locking mechanism. We have seen other developers using the Backendless Counters and Backendless Cache API to implement this.

Regards,
Mark

The update is performed through a transaction. But the retrieval is performed outside.
In your example, both retrieval and update operations are performed outside transaction.

  1. User A fetch object X using normal object retrieval API
  2. User A retrieve a specific property value of object X
  3. User A adds/deducts that value of object X
  4. User A apply updates through Unit of Work API

Is that still achievable? I mean, we want to ensure that whenever a user/client want to perform updates, he/she works with consistent, correct data.

I have looked through Backendless Counters. But there must be some kind of triggers/functions that keep the data and the counters synchronized, right? Especially for my use case.

Generally speaking if you want to make sure that the data is consistent (in other words multiple clients cannot modify the same object), you need to either use transactions or implement object/record locking.

When you talk about consistency, it is better to describe a scenario with multiple users. Could you rewrite the scenario below with User A and User B doing something in parallel?

  1. User A fetch object X using normal object retrieval API
  2. User A retrieve a specific property value of object X
  3. User A adds/deducts that value of object X
  4. User A apply updates through Unit of Work API

But using backendless counters do not perform any rollback, doesn’t it?
Developers have to implement this himself/herself. It can be tedious.
Then it means it is not a feasible solution.

Here’s how counters (or cache) can be used to implement object-locking:

Suppose you have an object with objectId X:

  1. Before you retrieve X, create a counter with the same name as objectId, the value can be anything, say 1. So you will have a counter with the name X and value 1.
  2. Retrieve the object and do any necessary changes to it.
  3. Write the object back to the database
  4. Remove counter X

When another client needs to be retrieve object X, check if there is a counter for X. If it exists, wait till the counter is gone (you need to periodically check for its existence. When the counter is gone, proceed with retrieval of X in that client.

The same thing can be done using real-time database. In case, you do not need counters and you’ll have a separate table that stores information about locked objects - same idea, there would be an object with information about X. Another client would check if a record in the locking table exists. If it does, subscribe to the real-time “delete” event. When the event arrives, it means the object had unlocked and you can proceed. This is not 100% reliable since it in an application with a lot of users, there may be contention for the same object and you may miss the time between when the object is unlocked and another client locks it.

Yeah, I have thought of all those scenario before but I think the real deal or benefit of using a transaction in this use case is rollback-“ing” capability. Using backendless counters, RT database and so on as you suggest is somewhat a tricky workaround, especially in sensitive data operation where data correctness and consistency is a must.

In the end, I decide to combine the power of Backendless Counters and Serializable Transaction API.
Thanks, Mark.
I am waiting for the “interim operation” feature to be released.

1 Like

Hi Mark,

Right now I am using Backendless Counters.
But as you may know, it does not survive connectivity drop unlike transaction which all should success or fail at the same time, classic ACID.

I use Backendless Counters at initial stage of data fetching to offer record/object lock, but if the client who accesses it loses internet connectivity, then the server may kept the counter value and not released/reset it, hence other clients can not access the locked object.

Any suggestion for this scenario?

Check the state of the counter when the client obtains connectivity.